struts2入门(二)启动和执行流程分析

2012/05/07 2018点热度 0人点赞 0条评论

启动过程图

启动服务器,加载web.xml文件

注:StrutsPreparedAndExecuteFilter过滤器是对 StrutsPrepareFilter和  StrutsExecuteFilter 两个过滤器的包装,配置上面的两个过滤器也可以实现struts中的机制

解析StrutsPreparedAndExecuteFilter过滤器

//在tomcat启动的时候,准备过程
protected PrepareOperations prepare; 
protected ExecuteOperations execute; 
//拦截器配置的非拦截的元素,比如,比如静态页面,图片等
 protected List<Pattern> excludedPatterns = null

 执行过滤器中的方法

  public void init(FilterConfig filterConfig) throws ServletException 只是在初始化的时候执行,在tomcat启动的时候执行此方法

FilterHostConfig config = new FilterHostConfig(filterConfig);
init.initLogging(config);
 /**  init.initDispatcher先使用FilterHostConfig 判断一下是否有过滤器的初始化参数
       如果有参数将参数组织放到一个list集合中
       创建Dispatcher,(读取资源文件文件的)会接受FilterHostConfig组织好的参数
       初始化Dispatcher, dispatcher.init()做的事            
           //加载org/apache/struts2/default.properties
          init_DefaultProperties();// [1]
               * 具体  configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());
                     *   defaultSettings = new PropertiesSettings("org/apache/struts2/default");
           //加载struts-default.xml,struts-plugin.xml,struts.xml
          init_TraditionalXmlConfigurations(); // [2]
              configPaths = DEFAULT_CONFIGURATION_PATHS;   是一个常量DEFAULT_CONFIGURATION_PATHS=struts-default.xml,struts-plugin.xml,struts.xml  在这里将拦截器都实例化了 
          init_LegacyStrutsProperties();   // [3]
          //用户自己实现的ConfigurationProviders类, 配置类全名和实现ConfigurationProvider接口,用逗号隔开即可            
          init_CustomConfigurationProviders(); // [5]
          //Filter的初始化参数
          init_FilterInitParameters() ;// [6]
          //初始化用户自定义的别名
          init_AliasStandardObjects() ;// [7]
                                                                                                                                                                    
   */
Dispatcher dispatcher = init.initDispatcher(config);
init.initStaticContentLoader(config, dispatcher);
//struts环境的准备过程
prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher);
//struts执行环境的准备过程
execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);
//excludedPatterns存放的是配置文件中所有自定义不拦截的请求或者资源
this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);

doFilter 每次url请求都会执行这个方法

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)

    doFilter是过滤器的执行方法,它拦截提交的HttpServletRequest请求,HttpServletResponse响应,

核心代码(注:以下代码有点乱,最好参考源代码,一个个的对比着点进去)

理解下面的代码首先得了解

//OgnlValueStack里面有两个重要的属性:  
   //CompoundRoot root  
   //transient Map<String, Object> context;  
//而context又是一个OgnlContext,OgnlContext也有两个重要的属性:  
   //private Object _root;  
   //private Map _values = new HashMap(23);
//设置默认编码和local  
prepare.setEncodingAndLocale(request, response); 
//根据拦截到的request和response创建Action上下文
prepare.createActionContext(request, response); 
      //解析createActionContext方法中的内容
        ActionContext ctx;
        Integer counter = 1;
        Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);
        if (oldCounter != null) {//如果存在表示曾经创建过ActionContext
             counter = oldCounter + 1;
        }
        //获取曾建创建的ActionContext对象                                       
        ActionContext oldContext = ActionContext.getContext();
        if (oldContext != null) {
            // detected existing context, so we are probably in a forward
             //创建当前流程的ActionContext对象,并将原有的对象的中的request的参数保存到新的ActionContext对象中,应该是在转发的时候用到
            ctx = new ActionContext(new HashMap<String, Object>(oldContext.getContextMap()));
        } else {
                                                 
             ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
                 /**
                public ValueStack createValueStack() {
                     //ValueStack是接口,其默认实现类是OgnlValueStack,所以实际上是new一个OgnlValueStack出来。
                    ValueStack stack = new OgnlValueStack(xworkConverter, compoundRootAccessor, textProvider, allowStaticMethodAccess);       
                       protected OgnlValueStack(XWorkConverter xworkConverter, CompoundRootAccessor accessor, TextProvider prov, boolean allowStaticAccess) {
                            setRoot(xworkConverter, accessor, new CompoundRoot(), allowStaticAccess);
                             //setRoot方法详解                          
                               this.root = compoundRoot;//OgnlValueStack.root = compoundRoot;
                               this.securityMemberAccess = new SecurityMemberAccess(allowStaticMethodAccess);//方法/属性访问策略
                               //创建context了,创建context使用的是ongl的默认方式。 
                               this.context = Ognl.createDefaultContext(this.root, accessor, new OgnlTypeConverterWrapper(xworkConverter), securityMemberAccess);
                               // 将OgnlValueStack放入到reuqest的指定的属性中VALUE_STACK=com.opensymphony.xwork2.util.ValueStack.ValueStack
                               context.put(VALUE_STACK, this);
                               Ognl.setClassResolver(context, accessor);
                               ((OgnlContext) context).setTraceEvaluations(false);
                               ((OgnlContext) context).setKeepLastEvaluation(false);   
                            push(prov);
                       }
                    container.inject(stack);
                    //把容器加入OgnlValueStack.context,实际是加入到OgnlContext的context中。
                    stack.getContext().put(ActionContext.CONTAINER, container);
                    return stack;
                }
                */
             stack.getContext().putAll(dispatcher.createContextMap(request, response, null, servletContext));
             ctx = new ActionContext(stack.getContext());
        }
        request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);
        ActionContext.setContext(ctx);
        return ctx;
//将处理后的编码,国际化和创建的actioncontext上下文绑定到tomcat创建的本地线程上去
 prepare.assignDispatcherToThread();
 //excludedPatterns非拦截的资源选项,
 if ( excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
   /**   prepare.isUrlExcluded(request, excludedPatterns)判断现在的request请求是否包含在不拦截的资源里
    */
   //放行
   chain.doFilter(request, response);
 } else {
 //request增强,在后台判断了表单的类型,主要是上传的时候对request进行包装
 request = prepare.wrapRequest(request);
 //实际是在prepare中的dispatcher中的解析的struts的配置文件中查找request过来的链接,返回一个actionMapping的映射(也就是在这里建立了请求和action中的方法的关联)调用的是defaultActionMapper
 ActionMapping mapping = prepare.findActionMapping(request, response, true);
 if (mapping == null) {
      /**就是如果path是以“/struts”开头,则到初始参数packages配置的包路径去查找对应的静态资源并输出到页面流中, 
       * 当然.class文件除外。如果再没有则跳转到404
       */
     boolean handled = execute.executeStaticResourceRequest(request, response);
     if (!handled) {
         chain.doFilter(request, response);
     }
 } else {
     //映射的请求存在,这个时候会在这里去执行mapping映射中的拦截器
     //映射的请求存在,这个时候会在这里去执行mapping映射中的拦截器找到对应action配置文件后,调用ExecuteOperations类中executeAction
     execute.executeAction(request, response, mapping);
                      /**
                          在这里执行了ExecuteOperations 类下的 dispatcher.serviceAction(request, response, servletContext, mapping);方法
                              ExecuteOperations在strutsPrepareAndExecuteFilter中已经声明过了 protected ExecuteOperations execute;
                                                                                                                        
                              然后进入dispatcher的serviceAction方法,在这里面生成了访问的代理对象,这里使用了aop编程的思想,将拦截器和目标方法织入到了代理方法中,
                               ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
                               namespace, name, method, extraContext, true, false);
                               //将本次请求生产的值栈valueStack放入到request请求中
                               request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
                              在serviceAction方法中
                                  proxy.execute();
                              代理对象执行的方法
                                StrutsActionProxy 中的execute(),
                                  * return invocation.invoke();
                                       *  真正执行的是 DefaultActionInvocation下的invoke()方法
                                          *  在这个invoke()方法下,依次遍历struts2默认栈的拦截器
                                           由于拦截器都实现了Interceptor接口,所以拦截器都能获得ActionInvocation
                                           ActionInvocation是一个action执行的上下文环境,里面封装了值栈等,操作request都是从值栈中去的值,
                                           可以说,拦截器中操作的对象都是值栈中的内容
                                                  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 {
                                         * 在DefaultActionInvocation下的init(ActionProxy proxy)下
                                            //这里遍历了配置文件中的拦截器,将拦截器都装到了interceptors中
                                             List<InterceptorMapping> interceptorList = new ArrayList<InterceptorMapping>(proxy.getConfig().getInterceptors());
                                             interceptors = interceptorList.iterator();
     */
  }
}

yxkong

这个人很懒,什么都没留下

文章评论