Tomcat源碼學(xué)習(xí)第2篇 - Bootstrap的初始化加載
在上一篇中我們說到Tomcat的啟動入口是Bootstrap,那么今天我們就來研究一下,Bootstrap類在啟動main方法之后是如何進(jìn)行各項初始化來提供后續(xù)程序的運行的。
1. Bootstrap.main()方法
在main方法中我們可以看到,首先是創(chuàng)建了一個Bootstrap對象,并行初始化了一些相關(guān)的類加載器等操作,然后將創(chuàng)建的對象賦值給了 daemon,然后通過運行時附帶的參數(shù)來選擇它后續(xù)對應(yīng)的操作,這里我們直接看到 start 這里。(具體參數(shù)攜帶可以查看Tomcat項目的bin/startup.sh文件)

public?static?void?main(String?args[])?{
?????//?實例化一個當(dāng)前Bootstrap引導(dǎo)類對象,并進(jìn)行類加載器的初始化,然后把該對象賦值給?daemon
????????synchronized?(daemonLock)?{
?????????...????
????????}
????????try?{
????????????String?command?=?"start";
????????????if?(args.length?>?0)?{
????????????????command?=?args[args.length?-?1];
????????????}
???//?執(zhí)行命令分支判斷
????????????if?(command.equals("startd"))?{
????????????????...
????????????}?else?if?(command.equals("stopd"))?{
????????????????...
????????????}?else?if?(command.equals("start"))?{???//?啟動?tomcat?時傳入的是?start?命令參數(shù),走此分支
????????????????daemon.setAwait(true);
????????????????//?加載初始化
????????????????daemon.load(args);
????????????????//?啟動
????????????????daemon.start();
????????????????if?(null?==?daemon.getServer())?{
????????????????????System.exit(1);
????????????????}
????????????}?else?if?(command.equals("stop"))?{
????????????????...
????????????}?else?if?(command.equals("configtest"))?{
????????????????...
????????????}?else?{
????????????????log.warn("Bootstrap:?command?\""?+?command?+?"\"?does?not?exist.");
????????????}
????????}?catch?(Throwable?t)?{
????????????...
????????}
????}
2. Bootstrap.load()方法
進(jìn)入load方法之后,我們可以看到它內(nèi)部實際是通過反射來調(diào)用 Catalina.load方法來進(jìn)行的初始化加載。
3. Catalina.load()方法
在這個方法中,他會創(chuàng)建一個用于解析 XML 文件的對象 digester,然后通過 configFile方法得到conf/server.xml文件,并對其進(jìn)行解析,得到server對象(通過查看conf/server.xml文件,我們可以看到整個配置文件中,最外層的標(biāo)簽就是server,其內(nèi)部再一層層的嵌套其余的標(biāo)簽)。
public?void?load()?{
????//?用于解析XML配置文件
????Digester?digester?=?createStartDigester();
????InputSource?inputSource?=?null;
????InputStream?inputStream?=?null;
????File?file?=?null;
????try?{
????????try?{
????????????//?定位到配置文件?server.xml
????????????file?=?configFile();
????????????inputStream?=?new?FileInputStream(file);
????????????inputSource?=?new?InputSource(file.toURI().toURL().toString());
????????}?catch?(Exception?e)?{
????????????...
????????}
????????try?{
????????????inputSource.setByteStream(inputStream);
????????????digester.push(this);
????????????//?調(diào)用?digester?對象真正的去解析?xml
????????????digester.parse(inputSource);
????????}?catch?(Exception?e)?{
????????????...
????????}
????????
????????try?{
????????????//?執(zhí)行server.init
????????????getServer().init();
????????}?catch?(LifecycleException?e)?{
????????????...
????????}
????}?finally?{
????????...
????}
}


拿到server對象之后,調(diào)用了一個 init方法,點擊該方法跳轉(zhuǎn)到對應(yīng)實現(xiàn)中

4. LifecycleBase.initInternal()方法
LifecycleBase是Tomcat中組件生命周期的統(tǒng)一管理接口的實現(xiàn)類,該類對相關(guān)組件的生命周期進(jìn)行了統(tǒng)一管理,通過剛剛的跳轉(zhuǎn),我們找到了LifecycleBase.initInternal方法,該方法為抽象方法,需要再跳轉(zhuǎn)到對應(yīng)的子類中,這是一種典型設(shè)計模式《模板模式》,在父類中定義好了整體的步驟,具體的實現(xiàn)由子類自己去實現(xiàn)。
5. StandardServer.initInternal()方法
DEBUG打上斷點,再按F7進(jìn)入方法內(nèi)部,來到StandardServer.initInternal處。
這方法中有兩處地方調(diào)用了初始化方法:
globalNamingResources.init() 和 service.init(),分別對應(yīng)著配置文件中的兩處子標(biāo)簽,我們將重點放在service的初始化操作中,Tomcat中的連接器Connector與容器Engine都在這里。
Tomcat中支持多個service的配置,所以此處需要遍歷進(jìn)行初始化操作。

6. StandardService.initInternal()方法
通過service.init方法,我們又回到了生命周期基礎(chǔ)類中,重新調(diào)用initInternal方法進(jìn)入對應(yīng)的StandardService類中,在該類的initInternal方法中我們可以看到有engine和connector的初始化操作。

7. StandardEngine.initInternal()方法
繼續(xù)套娃,進(jìn)入StandardEngine查看具體實現(xiàn)。在這里得到對應(yīng)的Realm,然后返回。

8. Connector.initInternal()方法
繼續(xù)往下走,來到connector.init()這里,初始化連接器組件。繼續(xù)往下走,看到了有針對protocolHandler.init()的一個初始化操作。


9. AbstractProtocol.init()方法
先對endpoint對象進(jìn)行簡單的設(shè)置,然后再對其進(jìn)行初始化操作。
10. AbstractEndpoint.init()方法
這里主要是做一個端口的綁定,具體的實現(xiàn)由NioEndpoint來進(jìn)行實現(xiàn)
11. NioEndpoint.bind()方法
在該方法中我們可以看到他創(chuàng)建了一個socket通道,綁定了我們在配置文件中設(shè)置的IP地址與端口。
總結(jié)
到此Bootstrap.load()方法中的初始化操作基本就完結(jié)了,我們在配置文件中設(shè)置的各個組件的參數(shù)均已進(jìn)行初始化。
完整組件線路如下:
Server
?Service
??Connector
?? EndPoint:通信端點(TCP/IP)
?? Processor:報文解析(HTTP/AJP)
?? Adapter:轉(zhuǎn)換器
??Container
???Catalina
??? Engine:引擎,是Servlet容器Catalina的核心,它支持在其下定義多個虛擬主機
??? Host:虛擬主機,允許Tomcat引擎在將配置在一臺機器上的多個域名分割開來互相不干擾
??? Context:上下文對象
??? Wrapper:包裝組件
俄羅斯套娃:initInternal()
- END -我收集有眾多的 計算機電子書籍,有需要的小伙伴自提哦~
