您现在的位置是:首页 > 正文

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

2024-04-01 02:16:23阅读 5

启动过程图

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

启动服务器,加载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();
     */
  }
} 

网站文章

  • python获取星期几_如何在Python中获取日期的星期几?

    回答(15)2 years ago使用 weekday() (docs):&gt;&gt;&gt; import datetime&gt;&gt;&gt; datetime.datetime.toda...

    2024-04-01 02:15:42
  • Linux系统中如何查看TCP连接数

    初步认为是服务器资源不足了,但经反复测试,一旦连接上,不断点击同一个页面上不同的链接,都能迅速打开,这种现象就是说明apache最大连接数已经满了,新的访客只能排队等待有空闲的链接,而如果一旦连接上,...

    2024-04-01 02:15:31
  • 交换排序算法之快速排序-C语言版(带图详细)

    交换排序算法之快速排序-C语言版(带图详细)

    快速排序算法是在几种排序算法中效率最高的一个排序算法了,故称为快速排序,它的时间复杂度为:O(nlog2n),相比冒泡排序算法的O(n2)有很大的提升。

    2024-04-01 02:14:53
  • cesium入门(一)

    cesium入门(一)ygpGoogle 2020-09-22 19:21:17 697 收藏 4分类专栏: gis 文章标签: nodejs gis版权gis专栏收录该内容2 篇文章0 订阅订阅专栏...

    2024-04-01 02:14:42
  • 想学语言的模块化的同学可进来看看(以51单片机的模块化来讲解)

    想学语言的模块化的同学可进来看看(以51单片机的模块化来讲解)

    因为才刚刚接触程序半年,凭着本人有限的知识,只能从单片机来讲解这个模块化的相关知识. 首先讲讲写这篇博客的初衷,我们第一学期寒假的时候,我们的寒假作业要求就是得用模块化编写,网上看到的一些资料感觉看不懂,找了些大神给我讲解了之后才感觉明白了,自己用的时候还出现了很多的错误.为了让后面的学弟学妹们好好理解模块化写的第一篇博客.分模块的好处首先,这是我在写万年历和温度传感器的时候,显然这是我...

    2024-04-01 02:14:32
  • 第七周学习内容总结——区间dp、dfs

    第七周学习内容总结——区间dp、dfs

    本周学习内容一:本周学习了区间dp,今天又花一下午,终于弄懂这个经典题目(石子归并) 来看我的思考(O ^ ~ ^ O) #include #include #include #include #include #include #include #include using na

    2024-04-01 02:14:24
  • 仅需一个样本即可定制个性化的SAM

    仅需一个样本即可定制个性化的SAM

    仅需一个样本即可定制个性化的SAM

    2024-04-01 02:13:46
  • 最新php中es整合项目(Elasticsearch高级篇整合tp后台)

    最新php中es整合项目(Elasticsearch高级篇整合tp后台)

    以下后台使用thinkphp5.1、Elasticsearch7.14.1、ik分词器集成1索引列表2、添加索引3、设置字段4、添加文档5、修改文档6、查询索引并分页

    2024-04-01 02:13:37
  • 20050912:加把劲了

    向来以做事快著称的我,竟然成了项目里的瓶颈,郁闷~~~今天做了一天才把密码重置做完,然后就是email帐单和用户资料修改了。加油!为了不加班而加班!莫菲斯托,等着我蹂躏你吧(给我来两件绿色我就放了你)~~~~转载于:https://www.cnblogs.com/yidinghe/archive/2005/09/12/235407.html...

    2024-04-01 02:13:31
  • 基于学习的机械臂抓取研究综述

    基于学习的机械臂抓取研究综述

    本文主要总结了2020年的一篇机械臂抓取综述类的论文A Survey on Learning-Based Robotic Grasping,文末有本领域重点的一些论文。

    2024-04-01 02:12:53