前面的文章中,我們介紹了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容器時,會經過以下流轉步驟:
- Tomcat的連接器監聽SocketServer,發現這個請求,按照指定的協議和IO方式處理請求Socket訊息,決議Socket為對應的Request物體,并提供回寫報文的Response物體,
- 連接器將Request/Response交給Engine容器,Engine容器存盤了請求域名和Host容器之間的映射關系,比如"www.krishnan.com"域名對應于krishnan_webapps Host容器,
- Engine容器將請求交給對應的Host容器,Host容器開始決議請求中的路徑,如果配置了路徑和應用之間的關系,比如"/appB"對應于appB Context容器,Host容器會安裝配置將請求交給對應應用的Context容器,
- Host容器決議路徑并將應用交給Context容器之后,如果一個應用有多個Servlet,那么這個應用的Context容器也會包含多個Wrapper容器,我們可以通過路徑來將不同的請求映射到不同的Servlet容器,比如圖中的"/servletB"對應servletB Wrapper容器,Context容器將請求交給Wrapper容器,
- Context容器按照路徑將請求交給對應的Wrapper容器,Wrapper容器會加載對應的Servlet實作類,呼叫servlet實作類中的邏輯處理Request并將處理結果寫入Response中,

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都可以對應一個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

本文最先發布至微信公眾號,著作權所有,禁止轉載!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/304162.html
標籤:其他
