本系列文章将整理到我在GitHub上的《Java面試指南》倉庫,更多精彩内容請到我的倉庫裡檢視
https://github.com/h2pl/Java-Tutorial
喜歡的話麻煩點下Star哈
文章首發于我的個人部落格:
www.how2playlife.com
本文是微信公衆号【Java技術江湖】的《走進JavaWeb技術世界》其中一篇,本文部分内容來源于網絡,為了把本文主題講得清晰透徹,也整合了很多我認為不錯的技術部落格内容,引用其中了一些比較好的部落格文章,如有侵權,請聯系作者。
該系列博文會告訴你如何從入門到進階,從servlet到架構,從ssm再到SpringBoot,一步步地學習JavaWeb基礎知識,并上手進行實戰,接着了解JavaWeb項目中經常要使用的技術群組件,包括日志元件、Maven、Junit,等等内容,以便讓你更完整地了解整個Java Web技術體系,形成自己的知識架構。
為了更好地總結和檢驗你的學習成果,本系列文章也會提供每個知識點對應的面試題以及參考答案。
如果對本系列文章有什麼建議,或者是有什麼疑問的話,也可以關注公衆号【Java技術江湖】聯系作者,歡迎你參與本系列博文的創作和修訂。
走進JavaWeb技術世界5:初探Tomcat的HTTP請求過程
初探Tomcat的HTTP請求過程
前言:
1.作為Java開發人員,大多都對Tomcat不陌生,由Apache基金會提供技術支援與維護,因為其免費開源且易用,作為Web伺服器深受市場歡迎,是以有必要對其進行深入的研究,本系列皆以Tomcat 8.5為研究課題,下載下傳位址:
https://tomcat.apache.org/download-80.cgi2.下圖為 apache-tomcat-8.5.23.zip 在windows解壓後的目錄。
下面是解壓後的一些關鍵目錄:
* /bin - 啟動和停止服務等批處理檔案. ( *.sh) 檔案 (為Unix系統)、 (*.bat) 檔案 (for Windows系統)是一個功能性的複制檔案. 自從Win32 command-line 開始是一些單一的,缺乏功能的元件, 現在有一些拓展性的功能
* /conf - 配置檔案和一些相關的DTD檔案. 最重要的是 server.xml. 它是這個容器最主要的配置檔案.
* /logs - 日志檔案會列印到這裡
* /webapps - 這裡是你的應用程式部署的地方.
3.從最本質上講,tomcat為一個servlet容器,首先研究一下Tomcat的架構,如下圖:
架構诠釋:
1.Server(伺服器)是Tomcat構成的頂級構成元素,所有一切均包含在Server中,Server的實作類StandardServer可以包含一個到多個Services,Service的實作類為StandardService調用了容器(Container)接口,其實是調用了Servlet Engine(引擎),而且StandardService類中也指明了該Service歸屬的Server;
2.Container: 引擎(Engine)、主機(Host)、上下文(Context)和Wraper均繼承自Container接口,是以它們都是容器。但是,它們是有父子關系的,在主機(Host)、上下文(Context)和引擎(Engine)這三類容器中,引擎是頂級容器,直接包含是主機容器,而主機容器又包含上下文容器,是以引擎、主機和上下文從大小上來說又構成父子關系,雖然它們都繼承自Container接口。
3.連接配接器(Connector)将Service和Container連接配接起來,首先它需要注冊到一個Service,它的作用就是把來自用戶端的請求轉發到Container(容器),這就是它為什麼稱作連接配接器的原因。
從功能的角度将Tomcat源代碼分成5個子子產品,分别是:
Jsper子產品: 這個子子產品負責jsp頁面的解析、jsp屬性的驗證,同時也負責将jsp頁面動态轉換為java代碼并編譯成class檔案。在Tomcat源代碼中,凡是屬于org.apache.jasper包及其子包中的源代碼都屬于這個子子產品;
Servlet和Jsp子產品: 這個子子產品的源代碼屬于javax.servlet包及其子包,如我們非常熟悉的javax.servlet.Servlet接口、javax.servet.http.HttpServlet類及javax.servlet.jsp.HttpJspPage就位于這個子子產品中;
Catalina子產品: 這個子子產品包含了所有以org.apache.catalina開頭的java源代碼。該子子產品的任務是規範了Tomcat的總體架構,定義了Server、Service、Host、Connector、Context、Session及Cluster等關鍵元件及這些元件的實作,這個子子產品大量運用了Composite設計模式。同時也規範了Catalina的啟動及停止等事件的執行流程。從代碼閱讀的角度看,這個子子產品應該是我們閱讀和學習的重點。
Connector子產品: 如果說上面三個子子產品實作了Tomcat應用伺服器的話,那麼這個子子產品就是Web伺服器的實作。所謂連接配接器(Connector)就是一個連接配接客戶和應用伺服器的橋梁,它接收使用者的請求,并把使用者請求包裝成标準的Http請求(包含協定名稱,請求頭Head,請求方法是Get還是Post等等)。同時,這個子子產品還按照标準的Http協定,負責給用戶端發送響應頁面,比如在請求頁面未發現時,connector就會給用戶端浏覽器發送标準的Http 404錯誤響應頁面。
Resource子產品: 這個子子產品包含一些資源檔案,如Server.xml及Web.xml配置檔案。嚴格說來,這個子子產品不包含java源代碼,但是它還是Tomcat編譯運作所必需的。
Tomcat的組織結構
- Tomcat是一個基于元件的伺服器,它的構成元件都是可配置的,其中最外層的是Catalina servlet容器,其他元件按照一定的格式要求配置在這個頂層容器中。
Tomcat的各種元件都是在Tomcat安裝目錄下的/conf/server.xml檔案中配置的。
由Server.xml的結構看Tomcat的體系結構
<Server> //頂層類元素,可以包括多個Service
<Service> //頂層類元素,可包含一個Engine,多個Connecter
<Connector> //連接配接器類元素,代表通信接口
<Engine> //容器類元素,為特定的Service元件處理客戶請求,要包含多個Host
<Host> //容器類元素,為特定的虛拟主機元件處理客戶請求,可包含多個Context
<Context> //容器類元素,為特定的Web應用處理所有的客戶請求
</Context>
</Host>
</Engine>
</Connector>
</Service>
</Server>
實際源碼如下:
<?xml version='1.0' encoding='utf-8'?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<!-- Security listener. Documentation at /docs/config/listeners.html
<Listener className="org.apache.catalina.security.SecurityListener" />
-->
<!--APR library loader. Documentation at /docs/apr.html -->
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->
<Listener className="org.apache.catalina.core.JasperListener" />
<!-- Prevent memory leaks due to use of particular java/javax APIs-->
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<!-- Global JNDI resources
Documentation at /docs/jndi-resources-howto.html
-->
<GlobalNamingResources>
<!-- Editable user database that can also be used by
UserDatabaseRealm to authenticate users
-->
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<!-- A "Service" is a collection of one or more "Connectors" that share
a single "Container" Note: A "Service" is not itself a "Container",
so you may not define subcomponents such as "Valves" at this level.
Documentation at /docs/config/service.html
-->
<Service name="Catalina">
<!--The connectors can use a shared executor, you can define one or more named thread pools-->
<!--
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="150" minSpareThreads="4"/>
-->
<!-- A "Connector" represents an endpoint by which requests are received
and responses are returned. Documentation at :
Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)
Java AJP Connector: /docs/config/ajp.html
APR (HTTP/AJP) Connector: /docs/apr.html
Define a non-SSL HTTP/1.1 Connector on port 8080
-->
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<!-- A "Connector" using the shared thread pool-->
<!--
<Connector executor="tomcatThreadPool"
port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
-->
<!-- Define a SSL HTTP/1.1 Connector on port 8443
This connector uses the BIO implementation that requires the JSSE
style configuration. When using the APR/native implementation, the
OpenSSL style configuration is required as described in the APR/native
documentation -->
<!--
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS" />
-->
<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<!-- An Engine represents the entry point (within Catalina) that processes
every request. The Engine implementation for Tomcat stand alone
analyzes the HTTP headers included with the request, and passes them
on to the appropriate Host (virtual host).
Documentation at /docs/config/engine.html -->
<!-- You should set jvmRoute to support load-balancing via AJP ie :
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
-->
<Engine name="Catalina" defaultHost="localhost">
<!--For clustering, please take a look at documentation at:
/docs/cluster-howto.html (simple how to)
/docs/config/cluster.html (reference documentation) -->
<!--
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
-->
<!-- Use the LockOutRealm to prevent attempts to guess user passwords
via a brute-force attack -->
<Realm className="org.apache.catalina.realm.LockOutRealm">
<!-- This Realm uses the UserDatabase configured in the global JNDI
resources under the key "UserDatabase". Any edits
that are performed against this UserDatabase are immediately
available for use by the Realm. -->
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<!-- SingleSignOn valve, share authentication between web applications
Documentation at: /docs/config/valve.html -->
<!--
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
-->
<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log." suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
</Engine>
</Service>
</Server>
由上可得出Tomcat的體系結構:

圖一:Tomcat的體系結構
由上圖可看出Tomca的心髒是兩個元件:Connecter和Container。一個Container可以選擇多個Connecter,多個Connector和一個Container就形成了一個Service。Service可以對外提供服務,而Server伺服器控制整個Tomcat的生命周期。
Tomcat Server處理一個HTTP請求的過程
圖三:Tomcat Server處理一個HTTP請求的過程
1、使用者點選網頁内容,請求被發送到本機端口8080,被在那裡監聽的Coyote HTTP/1.1 Connector獲得。
2、Connector把該請求交給它所在的Service的Engine來處理,并等待Engine的回應。
3、Engine獲得請求localhost/test/index.jsp,比對所有的虛拟主機Host。
4、Engine比對到名為localhost的Host(即使比對不到也把請求交給該Host處理,因為該Host被定義為該Engine的預設主機),名為localhost的Host獲得請求/test/index.jsp,比對它所擁有的所有的Context。Host比對到路徑為/test的Context(如果比對不到就把該請求交給路徑名為“ ”的Context去處理)。
5、path=“/test”的Context獲得請求/index.jsp,在它的mapping table中尋找出對應的Servlet。Context比對到URL PATTERN為*.jsp的Servlet,對應于JspServlet類。
6、構造HttpServletRequest對象和HttpServletResponse對象,作為參數調用JspServlet的doGet()或doPost().執行業務邏輯、資料存儲等程式。
7、Context把執行完之後的HttpServletResponse對象傳回給Host。
8、Host把HttpServletResponse對象傳回給Engine。
9、Engine把HttpServletResponse對象傳回Connector。
10、Connector把HttpServletResponse對象傳回給客戶Browser。
參考文章
http://www.360doc.com/content/10/0730/19/61151_42573873.shtml https://my.oschina.net/leamon/blog/210133 https://www.cnblogs.com/xll1025/p/11366264.html https://www.cnblogs.com/small-boy/p/8042860.html微信公衆号
個人公衆号:程式員黃小斜
微信公衆号【程式員黃小斜】新生代青年聚集地,程式員成長充電站。作者黃小斜,職業是阿裡程式員,身份是斜杠青年,希望和更多的程式員交朋友,一起進步和成長!專注于分享技術、面試、職場等成長幹貨,這一次,我們一起出發。
關注公衆号後回複“2020”領取我這兩年整理的學習資料,涵蓋自學程式設計、求職面試、算法刷題、Java技術學習、計算機基礎和考研等8000G資料合集。
技術公衆号:Java技術江湖
微信公衆号【Java技術江湖】一位阿裡 Java 工程師的技術小站,專注于 Java 相關技術:SSM、SpringBoot、MySQL、分布式、中間件、叢集、Linux、網絡、多線程,偶爾講點Docker、ELK,同時也分享技術幹貨和學習經驗,緻力于Java全棧開發!
關注公衆号後回複“PDF”即可領取200+頁的《Java工程師面試指南》強烈推薦,幾乎涵蓋所有Java工程師必知必會的知識點。