zoukankan      html  css  js  c++  java
  • Struts2运行流程

    1.启动web应用程序

      在web.xml中配置了StrutsPrepareAndExecuteFilter拦截器,因此web应用程序启动时,服务器将创建StrutsPrepareAndExecuteFilter实例对象,并调用对象的init()完成初始化,init()方法在Filter的整个生命周期之后只会被执行一次

      在init()方法中,根据配置信息初始化PrepareOperations 和ExecuteOperations对象

    2.客户端发送请求

      在web.xml中配置的StrutsPrepareAndExecuteFilter拦截所有请求,因此,请求被拦截,调用doFilter方法

      在doFilter方法中,创建ActionContext对象,并将ActionContext对象放入ThreadLocal中

              判断当前请求是否为不需要拦截的请求,是,直接调用chain.doFilter方法放行

              否则,获取ActionMapping对象,判断该对象是否为nul

                如果是null,放行

                否则,调用ExecuteOperations的executeAction方法,在该方法中调用Dispatcher的serviceAction方法

          ActionMapping对象,就是struts.xml中的配置

    3.Dispatcher的serviceAction方法    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);  //创建ActionContext对象
                prepare.assignDispatcherToThread();
                if ( excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) { // 判断当前请求是否是action请求
                    chain.doFilter(request, response);
                } else {
                    request = prepare.wrapRequest(request);
                    ActionMapping mapping = prepare.findActionMapping(request, response, true);
      
    //创建ActionMapping对象,创建ActionMapping的过程要借助ActionMapper,如果ActionMapping对象不是null,将该对象放入request域中
    //mapping = dispatcher.getContainer().getInstance(ActionMapper.class).getMapping(request, dispatcher.getConfigurationManager());
    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); } }

    4.Dispatcher的serviceAction方法

      在该方法中,获取Configuration对象,根据Configuration创建ActionProxy,将控制权交给ActionProxy,调用ActionProxy的execute()

        public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,
                                  ActionMapping mapping) throws ServletException {
    
            Map<String, Object> extraContext = createContextMap(request, response, mapping, context); // 创建ValueStack的Map属性
    
            // 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
    " + 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) {
                sendError(request, response, context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
            } finally {
                UtilTimerStack.pop(timerKey);
            }
        }

    5.ActionProxy的execute方法

      调用ActionInvocation的invoke方法

        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;
        }

    6.ActionInvocation的invoke方法

      依次调用配置的所有拦截器的intercept方法

      调用到最后一个拦截器时,调用invokeActionOnly方法

        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 = (InterceptorMapping) 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);
            }
        }

    7.拦截器的Intercept方法

      实现拦截器的功能

    8.ActionInvocation的invokeActionOnly方法

      根据配置的顺序,依次调用拦截器的intercept方法,当拦截器调用完之后,调用invokeActionOnly方法,再该方法中调用invokeAction方法,调用目标action方法

    9.ActionInvocation的invokeAction方法

        protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {
            String methodName = proxy.getMethod();
    
            if (LOG.isDebugEnabled()) {
                LOG.debug("Executing action method = " + actionConfig.getMethodName());
            }
    
            String timerKey = "invokeAction: " + proxy.getActionName();
            try {
                UtilTimerStack.push(timerKey);
    
                boolean methodCalled = false;
                Object methodResult = null;
                Method method = null;
                try {
                    method = getAction().getClass().getMethod(methodName, EMPTY_CLASS_ARRAY);
                } catch (NoSuchMethodException e) {
                    // hmm -- OK, try doXxx instead
                    try {
                        String altMethodName = "do" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
                        method = getAction().getClass().getMethod(altMethodName, EMPTY_CLASS_ARRAY);
                    } catch (NoSuchMethodException e1) {
                        // well, give the unknown handler a shot
                        if (unknownHandlerManager.hasUnknownHandlers()) {
                            try {
                                methodResult = unknownHandlerManager.handleUnknownMethod(action, methodName);
                                methodCalled = true;
                            } catch (NoSuchMethodException e2) {
                                // throw the original one
                                throw e;
                            }
                        } else {
                            throw e;
                        }
                    }
                }
    
                if (!methodCalled) {
                    methodResult = method.invoke(action, EMPTY_OBJECT_ARRAY);
                }
    
                return saveResult(actionConfig, methodResult);
            } catch (NoSuchMethodException e) {
                throw new IllegalArgumentException("The " + methodName + "() is not defined in action " + getAction().getClass() + "");
            } catch (InvocationTargetException e) {
                // We try to return the source exception.
                Throwable t = e.getTargetException();
    
                if (actionEventListener != null) {
                    String result = actionEventListener.handleException(t, getStack());
                    if (result != null) {
                        return result;
                    }
                }
                if (t instanceof Exception) {
                    throw (Exception) t;
                } else {
                    throw e;
                }
            } finally {
                UtilTimerStack.pop(timerKey);
            }
        }

    10.ActionInvocation的executeResult方法

      invokeAction方法返回之后(表示目标action方法执行完成),调用executeResult方法,在该方法中调用Result的execute方法渲染结果

        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);
            }
        }

    11.结果返回之后的后续代码,将结果返回给客户端

    涉及的对象

    StrutsPrepareAndExecuteFilter

      doFilter方法,(1)创建ActionContext对象(2)如果该请求是需要拦截的请求,根据请求创建ActionMapping对象(3)如果ActionMapping对象不是null,则最终调用Dispatcher的serviceAction方法

    ActionMapping

      该对象中存放的就是struts.xml中配置的一个一个的<action>

      获取ActionMapping对象要借助ActionMapper对象

    ActionMapper

    Dispatcher

    ActionProxy

      通过ActionProxyFactory获取

    Configuration

    ConfigurationManager

    ActionInvocation

    Action

    Result

    总结:

    请求首先经过StrutsPrepareAndExecuteFilter

    调用dofilter方法

      如果该请求是需要拦截的请求,通过ActionMapper获取ActionMapping,如果ActionMapping不是null,表明再struts.xml中配置了该请求对应的<action>

    调用execute.executeAction(request, response, mapping);

    调用dispatcher.serviceAction(request, response, servletContext, mapping);

      先对值栈进行处理

        通过ActionMapping、ConfigurationManager、Configuration、ActionFactory获取ActionProxy

        将值栈放入request请求域中

        调用proxy.execute();

        调用retCode = invocation.invoke();

    如果当期拦截器不是最后一个,调用拦截器的intercept方法     resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this); 在每个拦截器的intercept方法最后return invocation.invoke(); 以这样的方式依次调用拦截器,直到最后一个拦截器

    如果当前拦截器是最后一个,调用ActionInvocation的invokeActionOnly方法  resultCode = invokeActionOnly();在拦截器调用完成之后,调用invokeAction方法执行目标Action方法  return invokeAction(getAction(), proxy.getConfig());

        调用invokeAction(getAction(), proxy.getConfig());

          String methodName = proxy.getMethod();

          method = getAction().getClass().getMethod(methodName, EMPTY_CLASS_ARRAY);

          methodResult = method.invoke(action, EMPTY_OBJECT_ARRAY);

    调用executeResult()方法渲染结果

      result = createResult();

      result.execute(this);

    依次执行每个拦截器的后续代码finally

    执行后续代码,将结果返回

  • 相关阅读:
    做了半年的答题小程序上线了
    党建答题助手小程序
    党建答题活动小程序
    微信答题活动小程序
    微信答题活动小程序
    如何搭建在线考试小程序
    如何搭建在线考试小程序
    基于云开发的在线答题小程序
    XLua访问C#中的List或者数组
    字符串、字节数组、流之间的相互转换以及文件MD5的计算
  • 原文地址:https://www.cnblogs.com/duanjiapingjy/p/9576486.html
Copyright © 2011-2022 走看看