學習Tomcat(五)之Context和Wrapper容器


前面的文章中,我們介紹了Tomcat的Engine和Host容器,我們知道一個Tomcat最多只有一個Engine容器,一個Engine容器可以包含多個Host容器,請求中的不同的Host對應不用的Host容器。本章我們會介紹Tomcat的另外兩個容器:Context容器和Wrapper容器。一個Host容器可以包含多個Context容器:同一個Host下面可以包含多個應用,每個應用對應一個Context容器。一個Context容器又可以包含多個Wrapper容器:每個Wrapper容器包含一個Servlet容器,意味着Tomcat允許一個應用有多個servlet實現。

Tomcat請求流程

我們現在知道Tomcat最重要的組件是連接器和四種類型的容器,下面的圖展示了Tomcat的一次請求是如何在連接器和四種容器之間流轉的,假設Http請求頭為"GET /appB/servletB/some-url HTTP/1.1 Host: www.krishnan.com",當請求訪問到Tomcat容器時,會經過以下流轉步驟:

  1. Tomcat的連接器監聽SocketServer,發現這個請求,按照指定的協議和IO方式處理請求Socket消息,解析Socket為對應的Request實體,並提供回寫報文的Response實體。
  2. 連接器將Request/Response交給Engine容器,Engine容器存儲了請求域名和Host容器之間的映射關系。比如"www.krishnan.com"域名對應於krishnan_webapps Host容器。
  3. Engine容器將請求交給對應的Host容器,Host容器開始解析請求中的路徑,如果配置了路徑和應用之間的關系,比如"/appB"對應於appB Context容器,Host容器會安裝配置將請求交給對應應用的Context容器。
  4. Host容器解析路徑並將應用交給Context容器之后,如果一個應用有多個Servlet,那么這個應用的Context容器也會包含多個Wrapper容器,我們可以通過路徑來將不同的請求映射到不同的Servlet容器。比如圖中的"/servletB"對應servletB Wrapper容器,Context容器將請求交給Wrapper容器。
  5. Context容器按照路徑將請求交給對應的Wrapper容器,Wrapper容器會加載對應的Servlet實現類,調用servlet實現類中的邏輯處理Request並將處理結果寫入Response中。

Tomcat請求流程

Context容器

我們在配置Tomcat應用程序的時候,總是需要配置一個web.xml文件,這個文件就是Context容器去解析的。tomcat默認的web.xml的配置如下所示,該配置中配置了兩個WrapperContext,分別對應於兩個Servlet配置。在web.xml中,我們經常可以看到listener標簽,主要是用於監聽Context容器的聲明周期事件。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
                      https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
  version="5.0">
  <request-character-encoding>UTF-8</request-character-encoding>
  <response-character-encoding>UTF-8</response-character-encoding>
    <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet>
        <servlet-name>jsp</servlet-name>
        <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
        <init-param>
            <param-name>fork</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>xpoweredBy</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>3</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

    <!-- The mappings for the JSP servlet -->
    <servlet-mapping>
        <servlet-name>jsp</servlet-name>
        <url-pattern>*.jsp</url-pattern>
        <url-pattern>*.jspx</url-pattern>
    </servlet-mapping>

    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

</web-app>

Wrapper容器

Wrapper容器

Wrapper容器是最小的容器,每個Wrapper都可以對應一個Servlet的實例。當請求轉發到Wrapper容器之后,wrapper容器在調用Pipeline方法之后,會使用特定的類加載器去加載servlet類,對servlet進行實例化和初始化,然后將請求交給servelt的service方法進行處理。

我們常見的Spring的DispatchServlet是線程安全的,所以Tomcat不需要保證Servlet的並發安全。對於非線程安全的servlet,則可以通過SingleThreadModel來保證多請求下servlet的正常運行。

Wrapper容器的主要作用就是載入servlet類並進行實例化,並調用service方法。當第一次請求某個servlet類的時候,Wrapper容器會載入servlet類。Tomcat提供了專門的類加載器用於加載servlet,關於這個類加載器我會在我的其它文章中介紹。

Wrapper容器的基本閥門StandardWrapperValve還會在調用servelt容器之前調用用戶配置的過濾器鏈Filter。

我是御狐神,歡迎大家關注我的微信公眾號:wzm2zsd

qrcode_for_gh_83670e17bbd7_344-2021-09-04-10-55-16

本文最先發布至微信公眾號,版權所有,禁止轉載!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM