JAVA WEB 技術是當今主流的互聯網WEB應用技術之一,而Servlet則是JAVA WEB 中的核心基礎。最近在看了《深刻分析Java Web技術內幕》(許令波 著)這本書發現了之前沒有看到的內容,就想對書中的內容進行總結,也方便本身之後的回顧,因此就有了這篇文章。java
經過這篇文章你將瞭解到如下內容:web
1.Servlet容器是如何工做 2.web應用中的Servlet如何建立 3.Servlet是如何被調用
在Tomcat中整個的體系結構中,Context容器直接管理Servlet在容器中的包裝類Wrapper,因此Context是真正管理Servlet的容器。經過圖咱們還能夠看出,一個Context對應着一個Web工程。在Tomcat配置文件中就能夠看出:apache
<Context path="/projectOne " docBase="D:\projects\projectOne" reloadable="true" />
既然Context容器如此的重要咱們就來了解下Tomcat是如何解析Context容器的。tomcat
首先,咱們已經知道了Context容器是Tomcat運行時的容器,它只有在添加web應用是被加載。服務器
public Context addWebapp(Host host, String url, String path) { silence(url); Context ctx = new StandardContext(); ctx.setPath( url ); ctx.setDocBase(path); if (defaultRealm == null) { initSimpleAuth(); } ctx.setRealm(defaultRealm); ctx.addLifecycleListener(new DefaultWebXmlListener()); ContextConfig ctxCfg = new ContextConfig(); ctx.addLifecycleListener(ctxCfg); ctxCfg.setDefaultWebXml("org/apache/catalin/startup/NO_DEFAULT_XML"); if (host == null) { getHost().addChild(ctx); } else { host.addChild(ctx); } return ctx; }
當一個WEB應用被添加時Tomcat將會建立一個StandardContext容器,並給這個Context容器設置必要的參數,URL和path分別表明這個應用在訪問路徑和這個應用實際的物理路徑。其中最重要的配置就是ContextConfig,這個類很是重要,是負責整個WEB應用的解析工做。app
咱們就來看看這個ContextConfig:框架
ContextConfig繼承了LifecycleListener接口,它是在調用addWebApp方法時被加入到StandardContext容器中的,負責整個web應用的配置文件解析工做。 自帶的init()方法和startInternal()方法最爲重要 1.init()主要完成如下工做 -建立用於解析的XML配置文件的contextDisester對象。 -讀取默認的context.xml配置文件,若是存在則解析。 -讀取默認的Host配置文件,若是存在則解析。 -讀取默認的Context自身的配置文件,若是存在則解析。 -設置Context的DocBase。 2. startInternal()方法 -建立讀取資源文件的對象 -建立ClassLoader對象。 -設置應用的工做目錄。 -啓動相關的輔助類。 -修改啓動狀態,通知感興趣的觀察者。 -子容器的初始化。 -獲取ServletContext並設置必要的參數 -初始化「load on startup」的Servlet。
最後將這個Context容器添加到父容器中,而後就是調用Tomcat的start方法啓動Tomcat。這樣就完成了整個WEB應用加載的前期工做。jsp
學過Javaweb基礎的同窗應該知道,web.xml是咱們整個web工程中不可缺乏的一個部分,若是你的項目中缺乏了它,可能就會致使一些
必要的BUG。同時,整個web應用的初始化主要也是解析這個文件,由於這個文件描述了你的web項目中一些關鍵信息,也是整個web項目的入口。url
接下來咱們來看下Tomcat是如何加載到這個如此重要的配置文件的。spa
1.首先會找到globalWebXml 2.接着會找到hostWebXml 3.最後是尋找應用的配置文件web.xml
完成以上的步驟以後,Tomcat會將web.xml中的相應屬性保存到WebXml對象中。如今不少的後臺web應用都已經升級到Servlet3.0了,若是你的項目也支持了這個版本,那麼在解析配置文件的時候,還要完成Servlet3.0中新增的特性的解析以及對annotat的支持。Servlet3.0在這裏就很少介紹了,他不是本文的重點內容。
將屬性存入WebXml對象後,也將相關的屬性設置到Context容器中,這些屬性包括Servlet,listener,filter,其中Servlet被包裝成具備容器屬性的StandardWrapper。
看到這裏咱們來對web.xml的做用進行一個總結
1.web應用的解析入口 2.做爲用來指定context容器屬性的配置文件
首先咱們來看看Tomcat是如何建立Servlet:
建立Servlet實例的方法是從Wrapper.loadServlet開始的,這個方法要完成的就是獲取servletClass,而後交給InstanceManager去建立一個基於servletClass.class的對象。
若是在web.xml中配置了 <jsp-file>。。。。</jsp-file>這個參數的話,在建立Servlet時初始化的就不是你本身編寫的JAVA類了,而是conf/web.xml中的org.apache.jasper.servlet.JspServlet。
Servlet的初始化操做是在StandardWrapper的initServlet方法中完成的,做用就是調用Servlet的init(),同時將StandardWrapperFacade做爲ServletConfig傳給Servlet。
StandardWrapperFacade的做用就是從StandardWrapper中拿到的數據只是ServltConfig中規定的數據,而不把不關心的數據暴露給Servlet,起到了對數據封裝的做用。
若是初始化的是JspServlet,那Tomcat會模擬一次請求,去請求這個JSP文件,爲的是將這個jsp文件編譯成類,並初始化這個類,用於後面的使用。
在前面的內容中咱們瞭解了Servlet的加載、建立、初始化,下面的內容中咱們就來看看Servlet是如何被調用的。
用戶向服務器發送請求一般包含的信息:
http://hosthome:port/contextpath/servletpath 其中 hosthome 和 port 用於與服務器創建TCP鏈接,然後面的URL則是用戶請求服務器中的某個子容器的數據。
咱們以Tomcat這個經常使用的容器來講明服務器是如何根據這個URL找到正確的Servlet容器。
在Tomcat中這種映射工做是由org.apache.tomcat.util.http.mapper這個專門的類去處理的。 這個類保存了Tomcat的Container容器中全部子容器的信息,當請求的Request類進入Container容器以前, Mapper將會根據此次請求的hostname和contextPath將host和context容器設置到Request的mappingData屬性中。
因此在請求進入容器以前就已經知道要訪問那個子容器。
在知道要訪問那個子容器後,接下來就是要執行Servlet的service方法。咱們一般的作法就是不繼承javax.servlet.servlet接口更爲簡單的HttpServlet類。
可是如今的WEB應用已經直接使用Servlet來完成用戶的交互邏輯了,而是使用更爲高效的MVC框架來完成這些任務。
而這些框架的入口也是Servlet的Service方法。
當Servlet從Servlet容器中移除時,也就說明Servlet的生命週期就結束了,這時Servlet的destroy方法將被調用,作一些掃尾工做。
這篇文章是個人第一篇文章,若是有寫的很差的地方,請各位大佬輕噴,小弟再此跪謝了。