Struts2执行流程

来源:互联网 发布:恒扬数据股份有限公司 编辑:程序博客网 时间:2024/06/06 02:09

ActionMapping:在一个web应用中,每个资源都必须通过URI来进行引用。 资源包括HTML页面,JSP页面,和定制动作。为了给定制动作一个 URI或者说路径,Struts框架提供了一个 ActionMapping对象保存当前Action状态的一个类,struts.xml文件中的一个<action>标签,通常要指定name和namespace

ActionMapper:ActionMapper可能会返回一个ActionMapping,如果返回一个ActionMapping对象的话,说明是一个struts请i去,如果返回一个null,责说明没有一个Action和它相匹配,是一个非struts请求

ActionProxy:通过webwork和xwork交互关系图可以看出,它是action和xwork中间的一层。 正因为ActionProxy的存在导致Action调用更加简洁。

ActionInvocation:一个ActionInvocation包含了一系列的拦截器,通过反复的进行invoke()方法,执行action,执行相应结果。

Struts2运行图解

核心控制器2.1.3版本之后,struts的filterDispatcher核心控制器变成了StrutsPrepareAndExecuteFilte,如图:


struts2 运行流程

  • 请求发给StrutsPrepareAndExecuteFilter
  • StrutsPrepareAndExecuteFilter询问ActionMapper;该请求是否是一个Struts2请求(即是否返回一个非空的ActionMapping对象)
  • 若ActionMapping认为该请求是一个Struts2请求,啧StrutsPrepareAndExecuteFilter把请求处理交给ActionProxy。
  • ActionProxy通过Configuration Manager询问框架的配置文件(即struts.xml),确定需要调用的Action类及action方法。
  • ActionProxy创建一个ActionInvocation的实例,并进行初始化
  • ActionInvocation实例在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。
  • Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。调用结果的execute方法,渲染结果。在渲染的过程中可能使用struts2框架中的标签。
  • 执行各个拦截器invocation.invoke()之后的代码
  • 把结果发送给客户端
源码
  • 请求发给StrutsPrePareAndExecuteFilter类的doFilter方法
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {        HttpServletRequest request = (HttpServletRequest) req;        HttpServletResponse response = (HttpServletResponse) res;        try {            prepare.setEncodingAndLocale(request, response);            prepare.createActionContext(request, response);            prepare.assignDispatcherToThread();            if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {                chain.doFilter(request, response);            } else {                request = prepare.wrapRequest(request);                //获取一个ActionMapping对象,如果对象返回空,说明该请求是一个非Struts请求                ActionMapping mapping = prepare.findActionMapping(request, response, true);                if (mapping == null) {                    boolean handled = execute.executeStaticResourceRequest(request, response);                    if (!handled) {                        chain.doFilter(request, response);                    }                } else {                    execute.executeAction(request, response, mapping);                }            }        } finally {            prepare.cleanupRequest(request);        }}
15行,进入findActionMapping方法。获取了一个ActionMapping对象,如果对象是空,是一个非Struts请求,紧接着chain.dofilter(request,response);
21行,如果ActionMapping不为空,那么执行executeAction方法
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,                              ActionMapping mapping) throws ServletException {        Map<String, Object> extraContext = createContextMap(request, response, mapping, context);        // If there was a previous value stack, then create a new copy and pass it in to be used by the new Action        ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);        boolean nullStack = stack == null;        if (nullStack) {            ActionContext ctx = ActionContext.getContext();            if (ctx != null) {                stack = ctx.getValueStack();            }        }        if (stack != null) {            extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack));        }        String timerKey = "Handling request from Dispatcher";        try {            UtilTimerStack.push(timerKey);            String namespace = mapping.getNamespace();            String name = mapping.getName();            String method = mapping.getMethod();            Configuration config = configurationManager.getConfiguration();            ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(                    namespace, name, method, extraContext, true, false);            request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());            // if the ActionMapping says to go straight to a result, do it!            if (mapping.getResult() != null) {                Result result = mapping.getResult();                result.execute(proxy.getInvocation());            } else {                proxy.execute();            }            // If there was a previous value stack then set it back onto the request            if (!nullStack) {                request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);            }        } catch (ConfigurationException e) {        // WW-2874 Only log error if in devMode            if (devMode) {                String reqStr = request.getRequestURI();                if (request.getQueryString() != null) {                    reqStr = reqStr + "?" + request.getQueryString();                }                LOG.error("Could not find action or result\n" + reqStr, e);            } else {                if (LOG.isWarnEnabled()) {                    LOG.warn("Could not find action or result", e);                }            }            sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e);        } catch (Exception e) {            if (handleException || devMode) {                sendError(request, response, context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);            } else {                throw new ServletException(e);            }        } finally {            UtilTimerStack.pop(timerKey);        }}
27行,createActionProxy创建ActionProxy,
public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map<String, Object> extraContext, boolean executeResult, boolean cleanupContext) {                ActionInvocation inv = new DefaultActionInvocation(extraContext, true);        container.inject(inv);        return createActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);}
5行
public ActionProxy createActionProxy(ActionInvocation inv, String namespace, String actionName, String methodName, boolean executeResult, boolean cleanupContext) {                StrutsActionProxy proxy = new StrutsActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);        container.inject(proxy);        proxy.prepare();        return proxy;}

5行,创建好了一个ActionProxy对象并返回,里面包含了className还有methodName(我的是默认的execute方法)
37行,执行proxy.execute方法,一路往下执行
public String execute() throws Exception {        ActionContext nestedContext = ActionContext.getContext();        ActionContext.setContext(invocation.getInvocationContext());        String retCode = null;        String profileKey = "execute: ";        try {            UtilTimerStack.push(profileKey);            retCode = invocation.invoke();        } finally {            if (cleanupContext) {                ActionContext.setContext(nestedContext);            }            UtilTimerStack.pop(profileKey);        }        return retCode;    }
11行,invocation.invoke方法
public String invoke() throws Exception {        String profileKey = "invoke: ";        try {            UtilTimerStack.push(profileKey);            if (executed) {                throw new IllegalStateException("Action has already executed");            }            if (interceptors.hasNext()) {                final InterceptorMapping interceptor = interceptors.next();                String interceptorMsg = "interceptor: " + interceptor.getName();                UtilTimerStack.push(interceptorMsg);                try {                                resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);                            }                finally {                    UtilTimerStack.pop(interceptorMsg);                }            } else {                resultCode = invokeActionOnly();            }            // this is needed because the result will be executed, then control will return to the Interceptor, which will            // return above and flow through again            if (!executed) {                if (preResultListeners != null) {                    for (Object preResultListener : preResultListeners) {                        PreResultListener listener = (PreResultListener) preResultListener;                        String _profileKey = "preResultListener: ";                        try {                            UtilTimerStack.push(_profileKey);                            listener.beforeResult(this, resultCode);                        }                        finally {                            UtilTimerStack.pop(_profileKey);                        }                    }                }                // now execute the result, if we're supposed to                if (proxy.getExecuteResult()) {                    executeResult();                }                executed = true;            }            return resultCode;        }        finally {            UtilTimerStack.pop(profileKey);        }}
10行,判断是否还有下一个拦截器,可以来看一下里面拦截器的集合
<interceptor-stack name="defaultStack">                <interceptor-ref name="exception"/>                <interceptor-ref name="alias"/>                <interceptor-ref name="servletConfig"/>                <interceptor-ref name="i18n"/>                <interceptor-ref name="prepare"/>                <interceptor-ref name="chain"/>                <interceptor-ref name="scopedModelDriven"/>                <interceptor-ref name="modelDriven"/>                <interceptor-ref name="fileUpload"/>                <interceptor-ref name="checkbox"/>                <interceptor-ref name="multiselect"/>                <interceptor-ref name="staticParams"/>                <interceptor-ref name="actionMappingParams"/>                <interceptor-ref name="params">                    <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param>                </interceptor-ref>                <interceptor-ref name="conversionError"/>                <interceptor-ref name="validation">                    <param name="excludeMethods">input,back,cancel,browse</param>                </interceptor-ref>                <interceptor-ref name="workflow">                    <param name="excludeMethods">input,back,cancel,browse</param>                </interceptor-ref>                <interceptor-ref name="debugging"/>            </interceptor-stack>


没有配置拦截器栈,默认为defaultStack拦截器栈,看到第一个和最后一个相匹配
21行,执行目标方法;
public static void invokePrefixMethod(ActionInvocation actionInvocation, String[] prefixes) throws InvocationTargetException, IllegalAccessException {Object action = actionInvocation.getAction();String methodName = actionInvocation.getProxy().getMethod();if (methodName == null) {// if null returns (possible according to the docs), use the default execute         methodName = DEFAULT_INVOCATION_METHODNAME;}Method method = getPrefixedMethod(prefixes, methodName, action);if (method != null) {method.invoke(action, new Object[0]);}}
44行,执行result
private void executeResult() throws Exception {        result = createResult();        String timerKey = "executeResult: " + getResultCode();        try {            UtilTimerStack.push(timerKey);            if (result != null) {                result.execute(this);            } else if (resultCode != null && !Action.NONE.equals(resultCode)) {                throw new ConfigurationException("No result defined for action " + getAction().getClass().getName()                        + " and result " + getResultCode(), proxy.getConfig());            } else {                if (LOG.isDebugEnabled()) {                    LOG.debug("No result returned for action " + getAction().getClass().getName() + " at " + proxy.getConfig().getLocation());                }            }        } finally {            UtilTimerStack.pop(timerKey);        }    }
8行, 执行目标方法
public void execute(ActionInvocation invocation) throws Exception {        lastFinalLocation = conditionalParse(location, invocation);        doExecute(lastFinalLocation, invocation);    }
继续往下执行
 public void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {        if (LOG.isDebugEnabled()) {            LOG.debug("Forwarding to location " + finalLocation);        }        PageContext pageContext = ServletActionContext.getPageContext();        if (pageContext != null) {            pageContext.include(finalLocation);        } else {            HttpServletRequest request = ServletActionContext.getRequest();            HttpServletResponse response = ServletActionContext.getResponse();            RequestDispatcher dispatcher = request.getRequestDispatcher(finalLocation);            //add parameters passed on the location to #parameters            // see WW-2120            if (StringUtils.isNotEmpty(finalLocation) && finalLocation.indexOf("?") > 0) {                String queryString = finalLocation.substring(finalLocation.indexOf("?") + 1);                Map<String, Object> parameters = getParameters(invocation);                Map<String, Object> queryParams = urlHelper.parseQueryString(queryString, true);                if (queryParams != null && !queryParams.isEmpty())                    parameters.putAll(queryParams);            }            // if the view doesn't exist, let's do a 404            if (dispatcher == null) {                response.sendError(404, "result '" + finalLocation + "' not found");                return;            }            //if we are inside an action tag, we always need to do an include            Boolean insideActionTag = (Boolean) ObjectUtils.defaultIfNull(request.getAttribute(StrutsStatics.STRUTS_ACTION_TAG_INVOCATION), Boolean.FALSE);            // If we're included, then include the view            // Otherwise do forward            // This allow the page to, for example, set content type            if (!insideActionTag && !response.isCommitted() && (request.getAttribute("javax.servlet.include.servlet_path") == null)) {                request.setAttribute("struts.view_uri", finalLocation);                request.setAttribute("struts.request_uri", request.getRequestURI());                dispatcher.forward(request, response);            } else {                dispatcher.include(request, response);            }        }    }
41行,将页面进行转发,然后再执行倒序执行各个拦截器。把结果发送给客户端。



0 0
原创粉丝点击