• 详解web.xml中元素的加载顺序


    一、背景

      最近在项目中遇到了启动时出现加载service注解注入失败的问题,后来经过不懈努力发现了是因为web.xml配置文件中的元素加载顺序导致的,那么就抽空研究了以下tomcat在启动时web.xml文件中元素的加载顺序,现在和大家分享。

    二、问题剖析和研究结果

      遇到这种问题的时候,一般看源码是最直接和最权威的获取答案的方式,根据tomcat架构设计Context的实现类是StandardContext,全称org.apache.catalina.core.StandardContext。看到其实现Lifecycle接口,我们在StandardContext中找到startInternal方法,下面给出我把暂时无用的代码去掉后的注释版源码:

     1 /**
     2 * Start this component and implement the requirements
     3 * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
     4 *
     5 * @exception LifecycleException if this component detects a fatal error
     6 *  that prevents this component from being used
     7 */
     8 @Override
     9 protectedsynchronized void startInternal() throwsLifecycleException {
    10  //设置webappLoader 代码省略
    11  
    12  // Standard container startup 代码省略
    13  
    14   try{
    15  
    16     // Set up the context init params 
    17     //初始化context-param节点数据
    18     mergeParameters();
    19  
    20  
    21     // Configure and call application event listeners
    22     //配置和调用应用程序事件listeners 
    23     if(ok) {
    24       if(!listenerStart()) {
    25         log.error("Error listenerStart");
    26         ok = false;
    27       }
    28     }
    29  
    30     // Configure and call application filters
    31     //配置和调用应用程序filters
    32     if(ok) {
    33       if(!filterStart()) {
    34         log.error("Error filterStart");
    35         ok = false;
    36       }
    37     }
    38  
    39     // Load and initialize all "load on startup" servlets
    40     //加载和初始化配置在load on startup的servlets
    41     if(ok) {
    42       loadOnStartup(findChildren());
    43     }
    44  
    45     // Start ContainerBackgroundProcessor thread
    46     super.threadStart();
    47   }finally{
    48     // Unbinding thread
    49     unbindThread(oldCCL);
    50   }
    51  
    52 }

    那我们接着归纳和整理一下代码:

      1.首先初始化context-param节点

      2.接着配置和调用listeners 并开始监听

      3.然后配置和调用filters filters开始起作用

      4.最后加载和初始化配置在load on startup的servlets

    即元素加载顺序为:

    context-param --> listeners --> filters --> servlets

    注意:

      1.该加载顺序并不会受元素在web.xml文件中的位置的影响。

      2.但对于某类配置节而言,与它们出现的顺序是有关的。以 filter 为例,web.xml 中当然可以定义多个 filter,与 filter 相关的一个配置节是 filter-mapping,这里一定要注意,对于拥有相同 filter-name 的 filter 和 filter-mapping 配置节而言,filter-mapping 必须出现在 filter 之后,否则当解析到 filter-mapping 时,它所对应的 filter-name 还未定义。web 容器启动时初始化每个 filter 时,是按照 filter 配置节出现的顺序来初始化的,当请求资源匹配多个 filter-mapping 时,filter 拦截资源是按照 filter-mapping 配置节出现的顺序来依次调用 doFilter() 方法的。

    接着让我们来回忆一下web项目的启动顺序

      1.web容器读取web.xml配置文件,并首先读取<context-param>和<listener>两个结点。

      2.容器创建一个ServletContext(servlet上下文),该web项目的所有部分都将共享这个上下文。

      3.容器将<context-param>转换为键值对,并交给servletContext。

      4.容器按照load on startup中的启动顺序创建<listener>中的类实例,创建监听器。

    关于load on startup

      load-on-startup 元素在web应用启动的时候指定了servlet被加载的顺序,它的值必须是一个整数。

      如果它的值是一个负整数或是这个元素不存在,那么容器会在该servlet被调用的时候,加载这个servlet 。

      如果值是正整数或零,容器在配置的时候就加载并初始化这个servlet,容器必须保证值小的先被加载。如果值相等,容器可以自动选择先加载谁。

      正数的值越小,启动该servlet的优先级越高。

    三、总结

      通过研究源码我们明白了web.xml中各个元素的加载顺序,再遇到这种问题,我们就可以很快的定位出问题所在了。由此也发现和体会到了研究源码是一种很好的习惯也是解决问题不可缺少的方式。

  • 相关阅读:
    for循环中创建线程执行问题
    MySQL学习总结之路(第六章:表类型【存储引擎】的选择)
    Tensorflow的下载和安装
    C# 和 Python 的 hash_md5加密方法
    MySQL学习总结之路(第五章:函数)
    MySQL学习总结之路(第四章:运算符)
    MySQL学习总结之路(第三章:数据类型)
    MySQL学习总结之路(第二章:表)
    MySQL学习总结之路(服务与数据库管理)
    CSS居中的方式15种(水平垂直)
  • 原文地址:https://www.cnblogs.com/hafiz/p/5715349.html
Copyright © 2020-2023  润新知