<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試官:談?wù)?Tomcat 架構(gòu)及啟動過程,我一臉懵逼。。

          共 8423字,需瀏覽 17分鐘

           ·

          2021-06-17 22:36

          點(diǎn)擊關(guān)注公眾號,Java干貨及時送達(dá)

          來源:https://github.com/c-rainstorm/blog/tree/master/tomcat

          這個題目命的其實(shí)是很大的,寫的時候還是很忐忑的,但我盡可能把這個過程描述清楚。因?yàn)檫@是讀過源碼以后寫的總結(jié),在寫的過程中可能會忽略一些前提條件,如果有哪些比較突兀就出現(xiàn),或不好理解的地方可以給我提 Issue,我會盡快補(bǔ)充修訂相關(guān)內(nèi)容。

          很多東西在時序圖中體現(xiàn)的已經(jīng)非常清楚了,沒有必要再一步一步的作介紹,所以本文以圖為主,然后對部分內(nèi)容加以簡單解釋。

          繪制圖形使用的工具是 PlantUML + Visual Studio Code + PlantUML Extension

          本文對 Tomcat 的介紹以 Tomcat-9.0.0.M22 為標(biāo)準(zhǔn)。

          https://tomcat.apache.org/tomcat-9.0-doc/index.html

          Overview

          1. Bootstrap 作為 Tomcat 對外界的啟動類,在 $CATALINA_BASE/bin 目錄下,它通過反射創(chuàng)建 Catalina 的實(shí)例并對其進(jìn)行初始化及啟動。
          2. Catalina 解析 $CATALINA_BASE/conf/server.xml 文件并創(chuàng)建 StandardServer、StandardService、StandardEngine、StandardHost 等
          3. StandardServer 代表的是整個 Servlet 容器,他包含一個或多個 StandardService
          4. StandardService 包含一個或多個 Connector,和一個 Engine,Connector 和 Engine 都是在解析 conf/server.xml 文件時創(chuàng)建的,Engine 在 Tomcat 的標(biāo)準(zhǔn)實(shí)現(xiàn)是 StandardEngine
          5. MapperListener 實(shí)現(xiàn)了 LifecycleListener 和 ContainerListener 接口用于監(jiān)聽容器事件和生命周期事件。該監(jiān)聽器實(shí)例監(jiān)聽所有的容器,包括 StandardEngine、StandardHost、StandardContext、StandardWrapper,當(dāng)容器有變動時,注冊容器到 Mapper。
          6. Mapper 維護(hù)了 URL 到容器的映射關(guān)系。當(dāng)請求到來時會根據(jù) Mapper 中的映射信息決定將請求映射到哪一個 Host、Context、Wrapper。
          7. Http11NioProtocol 用于處理 HTTP/1.1 的請求
          8. NioEndpoint 是連接的端點(diǎn),在請求處理流程中該類是核心類,會重點(diǎn)介紹。
          9. CoyoteAdapter 用于將請求從 Connctor 交給 Container 處理。使 Connctor 和 Container 解耦。
          10. StandardEngine 代表的是 Servlet 引擎,用于處理 Connector 接受的 Request。包含一個或多個 Host(虛擬主機(jī)), Host 的標(biāo)準(zhǔn)實(shí)現(xiàn)是 StandardHost。
          11. StandardHost 代表的是虛擬主機(jī),用于部署該虛擬主機(jī)上的應(yīng)用程序。通常包含多個 Context (Context 在 Tomcat 中代表應(yīng)用程序)。Context 在 Tomcat 中的標(biāo)準(zhǔn)實(shí)現(xiàn)是 StandardContext。
          12. StandardContext 代表一個獨(dú)立的應(yīng)用程序,通常包含多個 Wrapper,一個 Wrapper 容器封裝了一個 Servlet,Wrapper的標(biāo)準(zhǔn)實(shí)現(xiàn)是 StandardWrapper。
          13. StandardPipeline 組件代表一個流水線,與 Valve(閥)結(jié)合,用于處理請求。StandardPipeline 中含有多個 Valve, 當(dāng)需要處理請求時,會逐一調(diào)用 Valve 的 invoke 方法對 Request 和 Response 進(jìn)行處理。特別的,其中有一個特殊的 Valve 叫 basicValve,每一個標(biāo)準(zhǔn)容器都有一個指定的 BasicValve,他們做的是最核心的工作。
          • StandardEngine 的是 StandardEngineValve,他用來將 Request 映射到指定的 Host;
          • StandardHost 的是 StandardHostValve, 他用來將 Request 映射到指定的 Context;
          • StandardContext 的是 StandardContextValve,它用來將 Request 映射到指定的 Wrapper;
          • StandardWrapper 的是 StandardWrapperValve,他用來加載 Rquest 所指定的 Servlet,并調(diào)用 Servlet 的 Service 方法。

          Tomcat init

          1. 通過從 CatalinaProperties 類中獲取 common.loader 等屬性,獲得類加載器的掃描倉庫。CatalinaProperties 類在的靜態(tài)塊中調(diào)用了 loadProperties() 方法,從 conf/catalina.properties 文件中加載了屬性.(即在類創(chuàng)建的時候?qū)傩跃鸵呀?jīng)加載好了)。
          2. 通過 ClassLoaderFactory 創(chuàng)建 URLClassLoader 的實(shí)例
          1. EngineConfig。LifecycleListener 的實(shí)現(xiàn)類,觸發(fā) Engine 的生命周期事件后調(diào)用,這個監(jiān)聽器沒有特別大的作用,就是打印一下日志
          2. HostConfig。LifecycleListener 的實(shí)現(xiàn)類,觸發(fā) Host 的生命周期事件后調(diào)用。這個監(jiān)聽器的作用就是部署應(yīng)用程序,這包括 conf/// 目錄下所有的 Context xml 文件 和 webapps 目錄下的應(yīng)用程序,不管是 war 文件還是已解壓的目錄。另外后臺進(jìn)程對應(yīng)用程序的熱部署也是由該監(jiān)聽器負(fù)責(zé)的。
          3. ContextConfig。LifecycleListener 的實(shí)現(xiàn)類,觸發(fā) Context 的生命周期事件時調(diào)用。這個監(jiān)聽器的作用是配置應(yīng)用程序,它會讀取并合并 conf/web.xml 和 應(yīng)用程序的 web.xml,分析 /WEB-INF/classes/ 和 /WEB-INF/lib/*.jar中的 Class 文件的注解,將其中所有的 Servlet、ServletMapping、Filter、FilterMapping、Listener 都配置到 StandardContext 中,以備后期使用。當(dāng)然了 web.xml 中還有一些其他的應(yīng)用程序參數(shù),最后都會一并配置到 StandardContext 中。

          Tomcat Start[Deployment]

          1. 解析 $CATALINA_BASE/conf/// 目錄下所有定義 Context 的 XML 文件,并添加到 StandardHost。這些 XML 文件稱為應(yīng)用程序描述符。正因?yàn)槿绱?,我們可以配置一個虛擬路徑來保存應(yīng)用程序中用到的圖片,詳細(xì)的配置過程請參考 開發(fā)環(huán)境配置指南 – 6.3. 配置圖片存放目錄
          2. 部署 $CATALINA_BASE/webapps 下所有的 WAR 文件,并添加到 StandardHost。
          3. 部署 $CATALINA_BASE/webapps 下所有已解壓的目錄,并添加到 StandardHost。

          特別的,添加到 StandardHost 時,會直接調(diào)用 StandardContext 的 start() 方法來啟動應(yīng)用程序。啟動應(yīng)用程序步驟請看 Context Start 一節(jié)。另外,MySQL 系列面試題和答案全部整理好了,微信搜索Java技術(shù)棧,在后臺發(fā)送:面試,可以在線閱讀。

          1. addListeners(engine) 方法會將該監(jiān)聽器添加到 StandardEngine 和它的所有子容器中
          2. registerHost() 會注冊所有的 Host 和他們的子容器到 Mapper 中,方便后期請求處理時使用。
          3. 當(dāng)有新的應(yīng)用(StandardContext)添加進(jìn)來后,會觸發(fā) Host 的容器事件,然后通過 MapperListener 將新應(yīng)用的映射注冊到 Mapper 中。

          Context Start

          • StandRoot 類實(shí)現(xiàn)了 WebResourceRoot 接口,它容納了一個應(yīng)用程序的所有資源,通俗的來說就是部署到 webapps 目錄下對應(yīng) Context 的目錄里的所有資源。因?yàn)槲覍?Tomcat 的資源管理部分暫時不是很感興趣,所以資源管理相關(guān)類只是做了簡單了解,并沒有深入研究源代碼。
          • resourceStart() 方法會對 StandardRoot 進(jìn)行初始配置
          • postWorkDirectory() 用于創(chuàng)建對應(yīng)的工作目錄 $CATALINA_BASE/work///, 該目錄用于存放臨時文件。
          • StardardContext 只是一個容器,而 ApplicationContext 則是一個應(yīng)用程序真正的運(yùn)行環(huán)境,相關(guān)類及操作會在請求處理流程看完以后進(jìn)行補(bǔ)充。
          • StardardContext 觸發(fā) CONFIGURE_START_EVENT 生命周期事件,ContextConfig 開始調(diào)用 configureStart() 對應(yīng)用程序進(jìn)行配置。
          1. 這個過程會解析并合并 conf/web.xml & conf///web.xml.default & webapps//WEB-INF/web.xml 中的配置。
          2. 配置配置文件中的參數(shù)到 StandardContext, 其中主要的包括 Servlet、Filter、Listener。
          3. 因?yàn)閺?Servlet3.0 以后是直接支持注解的,所以服務(wù)器必須能夠處理加了注解的類。Tomcat 通過分析 WEB-INF/classes/ 中的 Class 文件和 WEB-INF/lib/ 下的 jar 包將掃描到的 Servlet、Filter、Listerner 注冊到 StandardContext。
          4. setConfigured(true),是非常關(guān)鍵的一個操作,它標(biāo)識了 Context 的成功配置,若未設(shè)置該值為 true 的話,Context 會啟動失敗。

          Background process

          • 后臺進(jìn)程的作用就是處理一下 Servlet 引擎中的周期性事件,處理周期默認(rèn)是 10s。
          • 特別的 StandardHost 的 backgroundProcess() 方法會觸發(fā) Host 的 PERIODIC_EVENT 生命周期事件。然后 HostConfig 會調(diào)用其 check() 方法對已加載并進(jìn)行過重新部署的應(yīng)用程序進(jìn)行 reload 或?qū)π虏渴鸬膽?yīng)用程序進(jìn)行熱部署。熱部署跟之前介紹的部署步驟一致, reload() 過程只是簡單的順序調(diào)用 setPause(true)、stop()、start()、setPause(false),其中 setPause(true) 的作用是暫時停止接受請求。

          How to read excellent open source projects

          真正的第一次閱讀開源項(xiàng)目源代碼,收獲還是很大的。讓我在架構(gòu)設(shè)計(jì)、面向?qū)ο笏枷搿⒃O(shè)計(jì)模式、Clean Code等等各個方面都有了進(jìn)步。閱讀優(yōu)秀的開源項(xiàng)目其實(shí)是一件很爽的事,因?yàn)闀r不時的會發(fā)現(xiàn)一個新的設(shè)計(jì)思路,然后不由自主的感嘆一聲居然還可以這樣!

          當(dāng)然了,讀的時候還是會有一些痛點(diǎn)的,比如說碰到一個變量,但是死活就是找不到初始化的位置,有時通過 Find Usage 工具可以找到,但有些找不到的只能從頭開始再過一邊源碼。有時碰到一個設(shè)計(jì)思路死活都想不明白為什么這樣設(shè)計(jì)等等,這種情況就只能通過分析更高一層的架構(gòu)來解決了等等。

          下面我簡單分享一下我是如何閱讀開源項(xiàng)目源碼的。

          • 先找一些介紹該項(xiàng)目架構(gòu)的書籍來看,項(xiàng)目架構(gòu)是項(xiàng)目核心中的核心,讀架構(gòu)讀的是高層次的設(shè)計(jì)思路,讀源碼讀的是低層次的實(shí)現(xiàn)細(xì)節(jié)。有了高層次的設(shè)計(jì)思路做指導(dǎo),源碼讀起來才會得心應(yīng)手,因?yàn)樽x的時候心里很清楚現(xiàn)在在讀的源碼在整個項(xiàng)目架構(gòu)中處于什么位置。我在讀 Tomcat 源碼之前先把 《How Tomcat works》 一書過了一邊,然后又看了一下 《Tomcat 架構(gòu)解析》 的第二章,對 Tomcat 的架構(gòu)有了初步了解。(PS:《How Tomcat works》一書是全英文的,但讀起來非常流暢,雖然它是基于 Tomcat 4 和 5 的,但 Tomcat 架構(gòu)沒有非常大的變化,新版的 Tomcat 只是增加了一些組件,如果你要學(xué)習(xí) Tomcat 的話,首推這本書!)
          • 如果實(shí)在找不到講架構(gòu)的書,那就自己動手畫類圖吧!一般來說,開源項(xiàng)目都是為了提供服務(wù)的,我們把提供服務(wù)的流程作為主線來分析源代碼,這樣目的性會更強(qiáng)一些,將該流程中涉及到的類畫到類圖中,最后得到的類圖就是架構(gòu)!不過分析之前你要先找到流程的入口點(diǎn),否則分析就無從開始。以 Tomcat 為例,他的主線流程大致可以分為 3 個:啟動、部署、請求處理。他們的入口點(diǎn)就是 Bootstrap 類和 接受請求的 Acceptor 類!
          • 有了閱讀思路我們下面來說說工具吧。我使用的閱讀工具是 IntelliJ IDEA,一款十分強(qiáng)大的 IDE,可能比較重量級,如果你有其他更加輕量級的 Linux 平臺源碼閱讀工具,可以推薦給我~
          1. Structure 欄目可以自定義列出類中的域、方法,然后還可以按照繼承結(jié)構(gòu)對域和方法進(jìn)行分組,這樣就可以直接看出來域和方法是在繼承結(jié)構(gòu)中哪個類里定義的。當(dāng)你點(diǎn)擊方法和域時,還可以自動滾動到源代碼等等。
          2. 在源代碼中 點(diǎn)擊右鍵 -> Diagrams -> show Diagram 可以顯示類的繼承結(jié)構(gòu),圖中包含了該類所有的祖先和所有的接口。在該圖中選擇指定的父類和接口,點(diǎn)擊右鍵 -> show Implementations, IDEA 會列出接口的實(shí)現(xiàn)類或該類的子類。
          3. FindUsage、Go To Declaration 等等就不再多說了。

          最后,關(guān)注公眾號Java技術(shù)棧,在后臺回復(fù):面試,可以獲取我整理的 Java 系列面試題和答案,非常齊全。
          Reference
          https://www.amazon.com/How-Tomcat-Works-Budi-Kurniawan/dp/097521280X 
          http://product.dangdang.com/25084132.html
          https://tomcat.apache.org/tomcat-9.0-doc/index.html
          http://www-eu.apache.org/dist/tomcat/tomcat-9/v9.0.0.M22/src/






          關(guān)注Java技術(shù)??锤喔韶?/strong>



          獲取 Spring Boot 實(shí)戰(zhàn)筆記!
          瀏覽 41
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  一区二区三区高清 | 91嫩草私人成人亚洲影院 | 超碰p| 东北操逼网 | 在线高清免费无码 |