Tomcat架構解析(二)-----Connector、Tomcat啟動過程以及Server的創建過程


  Connector用於跟客戶端建立連接,獲取客戶端的Socket,交由Container處理。需要解決的問題有監聽、協議以及處理器映射等等。

  一、Connector設計

  Connector要實現的主要功能如下:

  

  設計圖如下:

  

  1、ProtocolHandler

  Connector中的ProtocolHandler用於處理不同的通信協議,Tomcat主要支持HTTP、AJP協議,並且支持BIO、NIO、APR等I/O方式。ProtocolHandler中使用AbstractEndpoint啟動Socket監聽,並且根據不同的I/O方式進行分類,例如NIO2Endpoint.

  獲取到客戶端Socket之后,需要根據請求地址映射到具體的容器進行處理。

  2、映射規則實現

  在獲取到客戶端的請求之后,需要根據請求地址映射到具體的容器中進行處理,主要是通過Mapper以及MapperListener兩個類實現映射功能。

  Mapper:維護容器映射信息。

  MappListener:實現了ContainerListener以及LifecycleListener接口,在容器組件狀態發生變更時,注冊或者取消對應的容器映射信息。

  因此到目前為止,Tomcat的架構圖如下所示:

  

  到目前為止,還沒有考慮到並發的問題,在客戶端大量請求的情況下,使用多線程技術是必不可少的,至於多線程為啥效率高?啥時候用多線程?使用多線程有啥注意事項?自行百度。。。。

  Tomcat提供了Executor接口,用於組件中的共享線程池,並且該接口集成了Lifecycle接口。Executor由Service維護,一個Service中的所有容器都可以共享此Executor。加入線程池后的Tomcat結構圖如下:

  

 

  二、Tomcat啟動

  Tomcat通過Catalina類來啟動Tomcat容器,Catalina提供了shell程序,用於解析server.xml文件,負責啟動、關閉Tomcat容器。另外Tomcat提供了Bootstrap類作為啟動的入口,Bootstrap創建一個Catalina實例。

  為啥有了Catalina還需要Bootstrap呢?因為Bootstrap依賴JRE,並通過反射調用Catalina實例,與Tomcat容器是松耦合的。並且為Tomcat創建共享類加載器,構造整個Tomcat服務器。

 

  Tomcat啟動過程如下:

  

  請求處理過程如下:

  

  

 三、Catalina

 Catalina其實就是Tomcat的servlet容器的實現,是Tomcat的核心,基於Servlet的web應用都需要servlet容器才能對外提供服務,例如SpringMVC等框架也是基於servlet。

 1、Digester

 Digester是將xml轉變為java對象的工具,是對sax的高層次的封裝。工作原理就是通過流來讀取xml文件,當碰到特定的xml節點執行特定的處理規則,一般為創建對象或是調用對象的某個方法。

 加上xml中的標簽都是成對出現的,如下所示:

 <a...>

       <b...>

              <c...>

              </c...>

       </b...> 

</a...>

 假設各個節點當中的處理規則都是創建對象,當Digester解析到a節點時,創建a對象,等到識別到</a>標簽時,此創建a對象的動作才算是完成。因此這里跟JVM中的方法執行是非常相似的,先進后出,因此Digester也是使用的棧結構來解析各個xml文件。

 當識別到<a>標簽時,將a對象放入到棧中,然后一直執行b、c標簽中的各個動作,當創建b對象時,則把b對象放入棧頂,如此循環,b對象創建完畢后,則調用a對象的某個方法,將b對象作為參數放入a中,最后識別到</a>標簽時,將對象從整個棧中移除,

 因此最終的結果是得到一個對象樹,並且子對象與父對象的關系也配置完成。常見的棧操作則如下所示:

 

  

  四、創建Server

  1、創建Server實例

  

  首先通過Catalina創建Digester對象,通過Digester創建Server對象,默認的Server實現類為StandardServer,當然可以通過自行指定實現類。

  a、addObjectCreate(String rule, String className,  String attributeName)

  設置節點與Java對象的映射規則,rule指定節點的篩選規則,className設置要創建的java類的名字,可以覆蓋要創建的默認Java類名稱。創建完對象后,放入棧頂。

  b、addSetProperties(String rule)

  此方法則是當遇到符合rule的節點時,將該節點中的屬性值獲取到,並根據反射將這些屬性注入到當前棧頂的對象中;

  eg:

  <?xml version="1.0" encoding="UTF-8?>
  <database>
        <user userName="guest" password="guest">
        </user>
  </database>

  digester.addSetProperties("database/user"),解析遇到user節點時,會獲取鍵值對 userName=guest,password=guest,獲得棧頂的dataBase對象,設置實例的userName、password屬性;

  c、addSetNext(String rule, String methodName)  

  設置當前rule節點與父節點的調用規則,當遇到rule節點時,調用棧中的次棧頂元素調用methodName方法。將棧頂元素作為次頂元素指定方法的輸入參數。

  比如:digester.addSetNext("database/user","addUser"),調用database實例的addUser,user為參數

 2、創建企業命名上下文

  

  3、為Server添加生命周期

  

  4、構造Service實例

  

  5、為Service添加生命周期

  

  6、Service中添加Executor

  

  7、為Service添加Connector

  

   addRule(String rule, Rule ruler):當解析到rule節點時,使用ruler規則處理器進行處理

  

  然后接下來就是為Connector添加虛擬主機SSL配置、Connector添加生命周期監聽器、Connector添加升級協議、Connector添加子元素解析規則

  接着后面就是Engine、Host、Context的解析,請關注后續博文~~~~~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM