Tomcat 7 中 web 應用加載原理(二)web.xml 解析

前一篇文章講了org.apache.catalina.startup.HostConfig的 lifecycleEvent 方法中所作的事情。最後看到在 Tomcat 啓動時或啓動後(後臺線程定時掃描)會調用 HostConfig 類的 deployApps 方法: java

能夠看到這裏部署應用有三種方式:XML 文件描述符、WAR 包、文件目錄。三種方式部署的整體流程很類似,都是一個 web 應用分配一個線程來處理,這裏統一放到與 Host 內部的線程池對象中( startStopExecutor ),因此有時會看到在默認配置下 Tomcat 啓動後可能有一個叫 -startStop-的線程還會運行一段時間才結束。但瀏覽這三種部署方式的實現代碼,裏面都是構建一個 Context 對象,並將構建好的 Context 對象與 Host 組件關聯起來(即調用 host.addChild(context)這句,具體代碼在 HostConfig 類的 deployDescriptor(ContextName cn, File contextXml)deployDirectory(ContextName cn, File dir)deployWAR(ContextName cn, File war)三個方法中,這裏再也不貼出代碼來詳細分析)。

前一篇文章只分析到這步,能夠看出與一個 web 應用相對應的一個 Context 對象已經構建出來了,但若是容器只執行到這裏根本沒法響應一個瀏覽器的一次請求。就 web 服務器的實現來看一次請求過來除了須要根據內部 Context 構建找到此次請求訪問的web應用具體所對應的 Context 對象,還須要包含 web 應用中具體的哪一個 Servlet 來處理此次請求,中間是否還須要執行相應的過濾器( filter )、監聽器( listener )等,作過 java 的 web 開發的同窗都知道,這些信息是配置在一個 web 應用的WEB-INF\web.xml文件的(servlet3 中已經支持將這些配置信息放到 Java 文件的註解中,但萬變不離其宗,總歸要在 web 應用的某個地方說明,並在容器啓動時加載,這樣才能真正提供 web 服務,響應請求)。web

看到這裏能夠猜到 Tomcat 容器加載 web 應用時一定會有對於每一個應用的 web.xml 文件的解析過程,本文就來看看這個解析過程。apache

在本文開頭提到的三種部署應用的實現代碼中有一些共通的代碼,這裏摘出來講明一下:瀏覽器

Class<?> clazz = Class.forName(host.getConfigClass());
LifecycleListener listener =
    (LifecycleListener) clazz.newInstance();
context.addLifecycleListener(listener);
複製代碼
host.addChild(context);  
複製代碼

第一段是在全部 Context 對象構建時會添加一個監聽器,這裏監聽器的類名是 StandardHost 類的實例變量 configClass ,其默認值就是org.apache.catalina.startup.ContextConfig。第二段是將當前構建的 Context 對象添加到父容器 Host 對象中。bash

先看 StandardHost 的 addChild 方法的實現: 服務器

能夠看到這段代碼最後調用了父類的 addChild 方法:
這裏看下 addChildInternal 方法的實現:
能夠看到會調用子容器的 start 方法,就是指調用 StandardContext 的 start 方法。

即給 host 對象添加子容器時將會調用子容器的 start 方法,按照前面文章的分析,調用 StandardContext 的 start 方法最終會調用org.apache.catalina.core.StandardContext類的 startInternal 方法(該方法代碼較長,建議本身閱讀,再也不貼出),這裏將會發布一系列事件,按調用先後順序這些事件包括:BEFORE_INIT_EVENTAFTER_INIT_EVENTBEFORE_START_EVENTCONFIGURE_START_EVENTSTART_EVENTAFTER_START_EVENTpost

前面提到在構建 Context 對象時都會註冊一個監聽器org.apache.catalina.startup.ContextConfig,看下這個類的 lifecycleEvent 方法中(爲何會執行這個方法能夠看這篇文章的分析)監聽了哪些事件: spa

與 Context 的 start 方法調用相關的事件監聽先後順序爲: AFTER_INIT_EVENT(執行 init 方法)、 BEFORE_START_EVENT(執行 beforeStart 方法)、 CONFIGURE_START_EVENT(執行 configureStart 方法)。

在 configureStart 方法將直接調用 webConfig 方法,正是在這個方法中將會解析 web.xml 文件: 線程

這個方法裏面作的事情,在英文註釋中說的很清楚了,歸納起來包括合併 Tomcat 全局 web.xml 、當前應用中的 web.xml 、web-fragment.xml 和 web 應用的註解中的配置信息,並將解析出的各類配置信息(如 servlet 配置、filter 配置等)關聯到 Context 對象中(在上面的代碼第 140 行: webXml.configureContext(context))。

看下 configureContext 方法: 3d

能夠看到裏面對 context 調用了各類 set、add 方法,從而將 web.xml 中的各類配置信息與表示一個 web 應用的 context 對象關聯起來。
相關文章
相關標籤/搜索