<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)及啟動過程,我一臉懵逼。。

          共 8685字,需瀏覽 18分鐘

           ·

          2021-06-22 16:42

          上一篇:深夜看了張一鳴的微博,讓我越想越后怕


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

          這個題目命的其實是很大的,寫的時候還是很忐忑的,但我盡可能把這個過程描述清楚。因為這是讀過源碼以后寫的總結(jié),在寫的過程中可能會忽略一些前提條件,如果有哪些比較突兀就出現(xiàn),或不好理解的地方可以給我提 Issue,我會盡快補充修訂相關(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 的實例并對其進(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)實現(xiàn)是 StandardEngine
          5. MapperListener 實現(xiàn)了 LifecycleListener 和 ContainerListener 接口用于監(jiān)聽容器事件和生命周期事件。該監(jiān)聽器實例監(jiān)聽所有的容器,包括 StandardEngine、StandardHost、StandardContext、StandardWrapper,當(dāng)容器有變動時,注冊容器到 Mapper。
          6. Mapper 維護了 URL 到容器的映射關(guān)系。當(dāng)請求到來時會根據(jù) Mapper 中的映射信息決定將請求映射到哪一個 Host、Context、Wrapper。
          7. Http11NioProtocol 用于處理 HTTP/1.1 的請求
          8. NioEndpoint 是連接的端點,在請求處理流程中該類是核心類,會重點介紹。
          9. CoyoteAdapter 用于將請求從 Connctor 交給 Container 處理。使 Connctor 和 Container 解耦。
          10. StandardEngine 代表的是 Servlet 引擎,用于處理 Connector 接受的 Request。包含一個或多個 Host(虛擬主機), Host 的標(biāo)準(zhǔn)實現(xiàn)是 StandardHost。
          11. StandardHost 代表的是虛擬主機,用于部署該虛擬主機上的應(yīng)用程序。通常包含多個 Context (Context 在 Tomcat 中代表應(yīng)用程序)。Context 在 Tomcat 中的標(biāo)準(zhǔn)實現(xiàn)是 StandardContext。
          12. StandardContext 代表一個獨立的應(yīng)用程序,通常包含多個 Wrapper,一個 Wrapper 容器封裝了一個 Servlet,Wrapper的標(biāo)準(zhǔn)實現(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 的實例
          1. EngineConfig。LifecycleListener 的實現(xiàn)類,觸發(fā) Engine 的生命周期事件后調(diào)用,這個監(jiān)聽器沒有特別大的作用,就是打印一下日志
          2. HostConfig。LifecycleListener 的實現(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 的實現(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ī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 系列面試題和答案全部整理好了,微信搜索互聯(lián)網(wǎng)架構(gòu)師,在后臺發(fā)送:2T,可以在線閱讀。

          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 類實現(xiàn)了 WebResourceRoot 接口,它容納了一個應(yīng)用程序的所有資源,通俗的來說就是部署到 webapps 目錄下對應(yīng) Context 的目錄里的所有資源。因為我對 Tomcat 的資源管理部分暫時不是很感興趣,所以資源管理相關(guān)類只是做了簡單了解,并沒有深入研究源代碼。
          • resourceStart() 方法會對 StandardRoot 進(jìn)行初始配置
          • postWorkDirectory() 用于創(chuàng)建對應(yīng)的工作目錄 $CATALINA_BASE/work///, 該目錄用于存放臨時文件。
          • StardardContext 只是一個容器,而 ApplicationContext 則是一個應(yīng)用程序真正的運行環(huán)境,相關(guān)類及操作會在請求處理流程看完以后進(jìn)行補充。
          • 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. 因為從 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

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

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

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

          • 先找一些介紹該項目架構(gòu)的書籍來看,項目架構(gòu)是項目核心中的核心,讀架構(gòu)讀的是高層次的設(shè)計思路,讀源碼讀的是低層次的實現(xiàn)細(xì)節(jié)。有了高層次的設(shè)計思路做指導(dǎo),源碼讀起來才會得心應(yīng)手,因為讀的時候心里很清楚現(xiàn)在在讀的源碼在整個項目架構(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 的話,首推這本書!)

          • 如果實在找不到講架構(gòu)的書,那就自己動手畫類圖吧!一般來說,開源項目都是為了提供服務(wù)的,我們把提供服務(wù)的流程作為主線來分析源代碼,這樣目的性會更強一些,將該流程中涉及到的類畫到類圖中,最后得到的類圖就是架構(gòu)!不過分析之前你要先找到流程的入口點,否則分析就無從開始。以 Tomcat 為例,他的主線流程大致可以分為 3 個:啟動、部署、請求處理。他們的入口點就是 Bootstrap 類和 接受請求的 Acceptor 類!

          • 有了閱讀思路我們下面來說說工具吧。我使用的閱讀工具是 IntelliJ IDEA,一款十分強大的 IDE,可能比較重量級,如果你有其他更加輕量級的 Linux 平臺源碼閱讀工具,可以推薦給我~

          1. Structure 欄目可以自定義列出類中的域、方法,然后還可以按照繼承結(jié)構(gòu)對域和方法進(jìn)行分組,這樣就可以直接看出來域和方法是在繼承結(jié)構(gòu)中哪個類里定義的。當(dāng)你點擊方法和域時,還可以自動滾動到源代碼等等。

            在源代碼中 點擊右鍵 -> Diagrams -> show Diagram 可以顯示類的繼承結(jié)構(gòu),圖中包含了該類所有的祖先和所有的接口。在該圖中選擇指定的父類和接口,點擊右鍵 -> show Implementations, IDEA 會列出接口的實現(xiàn)類或該類的子類。

            FindUsage、Go To Declaration 等等就不再多說了。

            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/


          感謝您的閱讀,也歡迎您發(fā)表關(guān)于這篇文章的任何建議,關(guān)注我,技術(shù)不迷茫!小編到你上高速。


              · END ·
          最后,關(guān)注公眾號互聯(lián)網(wǎng)架構(gòu)師,在后臺回復(fù):2T,可以獲取我整理的 Java 系列面試題和答案,非常齊全


          正文結(jié)束


          推薦閱讀 ↓↓↓

          1.不認(rèn)命,從10年流水線工人,到谷歌上班的程序媛,一位湖南妹子的勵志故事

          2.如何才能成為優(yōu)秀的架構(gòu)師?

          3.從零開始搭建創(chuàng)業(yè)公司后臺技術(shù)棧

          4.程序員一般可以從什么平臺接私活?

          5.37歲程序員被裁,120天沒找到工作,無奈去小公司,結(jié)果懵了...

          6.IntelliJ IDEA 2019.3 首個最新訪問版本發(fā)布,新特性搶先看

          7.漫畫:程序員相親圖鑒,笑屎我了~

          8.15張圖看懂瞎忙和高效的區(qū)別!

          一個人學(xué)習(xí)、工作很迷茫?


          點擊「閱讀原文」加入我們的小圈子!

          瀏覽 44
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  亚洲日韩精品视频在线 | www.成人黄色 | 国产精品久久久久久久久久梁医生 | 天天激情五月 | 综合 夜夜|