Tomcat - Tomcat 8.5.55 启动过程源码分析阶段二_load加载初始化
文章目錄
- 啟動(dòng)流程分析
- Pre
- load 加載初始化
- 總體預(yù)覽
- 源碼解析
- load()
- Server初始化
- Service初始化
- Engine初始化
- Connector 初始化
- 小結(jié)
啟動(dòng)流程分析
Pre
Tomcat - Tomcat 8.5.55 啟動(dòng)過(guò)程源碼分析階段一_init實(shí)例化Bootstrap
我們分析了 init 的主要功能,實(shí)例化Bootstrap , 調(diào)用init 通過(guò)反射調(diào)用Catalina#setParentClassLoader ,后面調(diào)用的load 和 start方法 均為 反射調(diào)用的Catalina對(duì)象的load和start 方法。
load 加載初始化
總體預(yù)覽
源碼解析
load()
我們梳理關(guān)鍵脈絡(luò)
// Digester對(duì)象 用于解析 server.xmlDigester digester = createStartDigester();// tomcat的配置文件 server.xmlfile = configFile();// 解析 xml 重點(diǎn)關(guān)注返回的對(duì)象 rootdigester.parse(inputSource);進(jìn)到這個(gè)parse方法
/*** Parse the content of the specified input source using this Digester.* Returns the root element from the object stack (if any).** @param input Input source containing the XML data to be parsed* @return the root object* @exception IOException if an input/output error occurs* @exception SAXException if a parsing exception occurs*/public Object parse(InputSource input) throws IOException, SAXException {configure();getXMLReader().parse(input);return root;}那我們看下我們source目錄下的精簡(jiǎn)后的server.xml
結(jié)合tomcat總體的架構(gòu)圖,套娃結(jié)構(gòu) , server-service-----connector/container-----engine-----host-----context-----wrapper
剛才debug出來(lái)的root對(duì)象是不是很好理解了呢?
我們看下LifeCycle接口的繼承關(guān)系, tomcat類的命名其實(shí)是很規(guī)范的 StandardXXXX
那繼續(xù)看下 root對(duì)象的 及 配置文件的關(guān)系
Server初始化
繼續(xù)往下跟
// Servier初始化getServer().init();調(diào)用的是 LifeCycle的init接口 , 跟進(jìn)去可以看到是進(jìn)入到了 LifeCycleBase這個(gè)抽象類的init方法
在init方法中 ,調(diào)用
// 初始化的關(guān)鍵方法 (抽象方法 交由子類實(shí)現(xiàn) 設(shè)計(jì)模式中的模板模式)initInternal();可以看到這個(gè)方法是抽象方法 , 具體的實(shí)現(xiàn)由繼承了LifeCycleBase這個(gè)抽象的子類實(shí)現(xiàn)具體的業(yè)務(wù)邏輯。
這里使用了模板模式 . 我們看下LifeCycleBase抽行類的具體實(shí)現(xiàn)
很規(guī)范的實(shí)現(xiàn) ,每個(gè)組件實(shí)例化 都要從LifeCycleBase中走一遍 ,自行實(shí)現(xiàn) init方法。
既然這里是Server, 那到StandardServer # initInternal 中看下
最重要的代碼 實(shí)例化Service
for (Service service : services) {service.init();}這里可以看出來(lái),Service 支持配置多個(gè),不過(guò)通常情況下,不建議這么做。 想配置多個(gè),干嘛不多起個(gè)tomcat呢?
Service初始化
同樣的模板模式 , 還是會(huì)調(diào)用到 StandardService # initInternal ,精簡(jiǎn)后的核心代碼如下
@Overrideprotected void initInternal() throws LifecycleException {super.initInternal();if (engine != null) {engine.init();} // Initialize our defined Connectorssynchronized (connectorsLock) {for (Connector connector : connectors) { connector.init(); }}}可以看到 StandardService # initInternal 中 主要干了兩件事兒 engine.init 和 connector.init
Engine初始化
同樣的老一套,模板模式, 跟進(jìn)到 StandardEngine # initInternal
@Overrideprotected void initInternal() throws LifecycleException { getRealm();super.initInternal();}可以看到調(diào)用的是父類的 initInternal , 父類 ContainerBase
@Overrideprotected void initInternal() throws LifecycleException {BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<>();startStopExecutor = new ThreadPoolExecutor(getStartStopThreadsInternal(),getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,startStopQueue,new StartStopThreadFactory(getName() + "-startStop-"));startStopExecutor.allowCoreThreadTimeOut(true);super.initInternal();}干了件啥事兒? 無(wú)非就是實(shí)例化了一個(gè)連接池startStopExecutor , 這個(gè)線程池的主要作用是在后面的start方法中使用。Engine可以配置多個(gè)Host,這個(gè)連接池的作用主要是為了并行初始化Host
Connector 初始化
繼續(xù) StandardService # initInternal , 接著 Connector 實(shí)例化, for循環(huán)嘛 ,一看就是支持配置多個(gè)Connector
for (Connector connector : connectors) { connector.init(); }Connector# initInternal
核心代碼
@Overrideprotected void initInternal() throws LifecycleException {super.initInternal();// Initialize adapter 并綁定 protocolHandleradapter = new CoyoteAdapter(this);protocolHandler.setAdapter(adapter);// protocolHandler初始化,主要是 內(nèi)部EndPoint的初始化 protocolHandler.init();}CoyoteAdapter 對(duì)應(yīng)tomcat架構(gòu)圖,是不是就是 Http 和 Servlet 之間用來(lái)做轉(zhuǎn)換的那個(gè)Adapter ?
protocolHandler.setAdapter(adapter) 綁定
繼續(xù)看
// protocolHandler初始化,主要是 內(nèi)部EndPoint的初始化 protocolHandler.init();進(jìn)入 AbstractHttp11Protocol # init
@Overridepublic void init() throws Exception { for (UpgradeProtocol upgradeProtocol : upgradeProtocols) {configureUpgradeProtocol(upgradeProtocol);}super.init();}關(guān)注 super.init(); 調(diào)用抽象父類AbstractProtocol ,精簡(jiǎn)后的代碼如下
@Overridepublic void init() throws Exception {String endpointName = getName();endpoint.setName(endpointName.substring(1, endpointName.length()-1));endpoint.setDomain(domain);// 通信端點(diǎn)的初始化endpoint.init();}核心: endpoint.init();
調(diào)用 AbstractEndpoint # init
public void init() throws Exception {if (bindOnInit) {bind();bindState = BindState.BOUND_ON_INIT;}}重點(diǎn)是bind 方法
NioEndpoint ,我們這里的版本是tomcat8+, 默認(rèn)的是NIO
精簡(jiǎn)后的核心代碼如下:
@Overridepublic void bind() throws Exception {if (!getUseInheritedChannel()) {// 獲取NIO 通道serverSock = ServerSocketChannel.open();socketProperties.setProperties(serverSock.socket());InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));// 綁定端口,但尚未使用accept獲取客戶端連接serverSock.socket().bind(addr,getAcceptCount());} }至此,load方法完畢
小結(jié)
通過(guò)一層層的分析,tomcat套娃式的設(shè)計(jì),使用模板模式,一層層的初始化 ,是不是有了更深刻的理解了呢?
load完了,接下來(lái)我們來(lái)看下start階段都干了啥事兒,繼續(xù)下一篇 ~
總結(jié)
以上是生活随笔為你收集整理的Tomcat - Tomcat 8.5.55 启动过程源码分析阶段二_load加载初始化的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Tomcat - Tomcat 8.5.
- 下一篇: Tomcat - Tomcat 8.5.