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的解析,請關注后續博文~~~~~