詳解web.xml中元素的加載順序

1、背景

  最近在項目中遇到了啓動時出現加載service註解注入失敗的問題,後來通過不懈努力發現了是由於web.xml配置文件中的元素加載順序致使的,那麼就抽空研究瞭如下tomcat在啓動時web.xml文件中元素的加載順序,如今和你們分享。web

2、問題剖析和研究結果

  遇到這種問題的時候,通常看源碼是最直接和最權威的獲取答案的方式,根據tomcat架構設計Context的實現類是StandardContext,全稱org.apache.catalina.core.StandardContext。看到其實現Lifecycle接口,咱們在StandardContext中找到startInternal方法,下面給出我把暫時無用的代碼去掉後的註釋版源碼:apache

 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 }

那咱們接着概括和整理一下代碼:tomcat

  1.首先初始化context-param節點架構

  2.接着配置和調用listeners 並開始監聽app

  3.而後配置和調用filters filters開始起做用webapp

  4.最後加載和初始化配置在load on startup的servletside

即元素加載順序爲:ui

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

注意:this

  1.該加載順序並不會受元素在web.xml文件中的位置的影響。spa

  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的優先級越高。

3、總結

  經過研究源碼咱們明白了web.xml中各個元素的加載順序,再遇到這種問題,咱們就能夠很快的定位出問題所在了。由此也發現和體會到了研究源碼是一種很好的習慣也是解決問題不可缺乏的方式。

相關文章
相關標籤/搜索