微信公衆號【Java技術江湖】一位阿里 Java 工程師的技術小站。(關注公衆號後回覆」Java「便可領取 Java基礎、進階、項目和架構師等免費學習資料,更有數據庫、分佈式、微服務等熱門技術學習視頻,內容豐富,兼顧原理和實踐,另外也將贈送做者原創的Java學習指南、Java程序員面試指南等乾貨資源)
前言:
1.做爲Java開發人員,大多都對Tomcat不陌生,由Apache基金會提供技術支持與維護,由於其免費開源且易用,做爲Web服務器深受市場歡迎,因此有必要對其進行深刻的研究,本系列皆以Tomcat 8.5爲研究課題,下載地址:https://tomcat.apache.org/download-80.cgihtml
2.下圖爲 apache-tomcat-8.5.23.zip 在windows解壓後的目錄。java
下面是解壓後的一些關鍵目錄:程序員
* /bin - 啓動和中止服務等批處理文件. ( *.sh) 文件 (爲Unix系統)、 (*.bat) 文件 (for Windows系統)是一個功能性的複製文件. 自從Win32 command-line 開始是一些單一的,缺少功能的組件, 如今有一些拓展性的功能 * /conf - 配置文件和一些相關的DTD文件. 最重要的是 server.xml. 它是這個容器最主要的配置文件. * /logs - 日誌文件會打印到這裏 * /webapps - 這裏是你的應用程序部署的地方.
3.從最本質上講,tomcat爲一個servlet容器,首先研究一下Tomcat的架構,以下圖:web
架構詮釋:面試
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接口。apache
3.鏈接器(Connector)將Service和Container鏈接起來,首先它須要註冊到一個Service,它的做用就是把來自客戶端的請求轉發到Container(容器),這就是它爲何稱做鏈接器的緣由。windows
從功能的角度將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編譯運行所必需的。
123456789101112 | < `Server> //頂層類元素,能夠包括多個Service <Service > //頂層類元素,可包含一個Engine,多個Connecter< Connector> //鏈接器類元素,表明通訊接口 <Engine > //容器類元素,爲特定的Service組件處理客戶請求,要包含多個Host< Host> //容器類元素,爲特定的虛擬主機組件處理客戶請求,可包含多個Context <Context > //容器類元素,爲特定的Web應用處理全部的客戶請求</ Context> </Host ></ Engine> </Connector ></ Service> </Server >` |
---|
實際源碼以下:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 | <? `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.htmlAPR (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 JSSEstyle configuration. When using the APR/native implementation, the OpenSSL style configuration is required as described in the APR/nativedocumentation --> <!--<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 processesevery request. The Engine implementation for Tomcat stand alone analyzes the HTTP headers included with the request, and passes themon 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 passwordsvia a brute-force attack --> <Realm` `className="org.apache.catalina.realm.LockOutRealm"> <!-- This Realm uses the UserDatabase configured in the global JNDIresources under the key "UserDatabase". Any edits that are performed against this UserDatabase are immediatelyavailable 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請求的過程
一、用戶點擊網頁內容,請求被髮送到本機端口8080,被在那裏監聽的Coyote HTTP/1.1 Connector得到。 二、Connector把該請求交給它所在的Service的Engine來處理,並等待Engine的迴應。 三、Engine得到請求localhost/test/index.jsp,匹配全部的虛擬主機Host。 四、Engine匹配到名爲localhost的Host(即便匹配不到也把請求交給該Host處理,由於該Host被定義爲該Engine的默認主機),名爲localhost的Host得到請求/test/index.jsp,匹配它所擁有的全部的Context。Host匹配到路徑爲/test的Context(若是匹配不到就把該請求交給路徑名爲「 」的Context去處理)。 五、path=「/test」的Context得到請求/index.jsp,在它的mapping table中尋找出對應的Servlet。Context匹配到URL PATTERN爲*.jsp的Servlet,對應於JspServlet類。 六、構造HttpServletRequest對象和HttpServletResponse對象,做爲參數調用JspServlet的doGet()或doPost().執行業務邏輯、數據存儲等程序。 七、Context把執行完以後的HttpServletResponse對象返回給Host。 八、Host把HttpServletResponse對象返回給Engine。 九、Engine把HttpServletResponse對象返回Connector。 十、Connector把HttpServletResponse對象返回給客戶Browser。