日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Tomcat - Tomcat 8.5.55 启动过程源码分析阶段二_load加载初始化

發(fā)布時間:2025/3/21 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Tomcat - Tomcat 8.5.55 启动过程源码分析阶段二_load加载初始化 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 啟動流程分析
  • Pre
  • load 加載初始化
    • 總體預(yù)覽
    • 源碼解析
      • load()
        • Server初始化
          • Service初始化
            • Engine初始化
            • Connector 初始化
  • 小結(jié)


啟動流程分析


Pre

Tomcat - Tomcat 8.5.55 啟動過程源碼分析階段一_init實(shí)例化Bootstrap

我們分析了 init 的主要功能,實(shí)例化Bootstrap , 調(diào)用init 通過反射調(diào)用Catalina#setParentClassLoader ,后面調(diào)用的load 和 start方法 均為 反射調(diào)用的Catalina對象的load和start 方法。


load 加載初始化

總體預(yù)覽

源碼解析

load()

我們梳理關(guān)鍵脈絡(luò)

// Digester對象 用于解析 server.xmlDigester digester = createStartDigester();// tomcat的配置文件 server.xmlfile = configFile();// 解析 xml 重點(diǎn)關(guān)注返回的對象 rootdigester.parse(inputSource);

進(jìn)到這個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目錄下的精簡后的server.xml

結(jié)合tomcat總體的架構(gòu)圖,套娃結(jié)構(gòu) , server-service-----connector/container-----engine-----host-----context-----wrapper

剛才debug出來的root對象是不是很好理解了呢?

我們看下LifeCycle接口的繼承關(guān)系, tomcat類的命名其實(shí)是很規(guī)范的 StandardXXXX

那繼續(xù)看下 root對象的 及 配置文件的關(guān)系

Server初始化

繼續(xù)往下跟

// Servier初始化getServer().init();

調(diào)用的是 LifeCycle的init接口 , 跟進(jìn)去可以看到是進(jìn)入到了 LifeCycleBase這個抽象類的init方法

在init方法中 ,調(diào)用

// 初始化的關(guān)鍵方法 (抽象方法 交由子類實(shí)現(xiàn) 設(shè)計模式中的模板模式)initInternal();

可以看到這個方法是抽象方法 , 具體的實(shí)現(xiàn)由繼承了LifeCycleBase這個抽象的子類實(shí)現(xiàn)具體的業(yè)務(wù)邏輯。

這里使用了模板模式 . 我們看下LifeCycleBase抽行類的具體實(shí)現(xiàn)

很規(guī)范的實(shí)現(xiàn) ,每個組件實(shí)例化 都要從LifeCycleBase中走一遍 ,自行實(shí)現(xiàn) init方法。

既然這里是Server, 那到StandardServer # initInternal 中看下

最重要的代碼 實(shí)例化Service

for (Service service : services) {service.init();}

這里可以看出來,Service 支持配置多個,不過通常情況下,不建議這么做。 想配置多個,干嘛不多起個tomcat呢?


Service初始化

同樣的模板模式 , 還是會調(diào)用到 StandardService # initInternal ,精簡后的核心代碼如下

@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();}

干了件啥事兒? 無非就是實(shí)例化了一個連接池startStopExecutor , 這個線程池的主要作用是在后面的start方法中使用。Engine可以配置多個Host,這個連接池的作用主要是為了并行初始化Host


Connector 初始化

繼續(xù) StandardService # initInternal , 接著 Connector 實(shí)例化, for循環(huán)嘛 ,一看就是支持配置多個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 對應(yīng)tomcat架構(gòu)圖,是不是就是 Http 和 Servlet 之間用來做轉(zhuǎn)換的那個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 ,精簡后的代碼如下

@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

精簡后的核心代碼如下:

@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é)

通過一層層的分析,tomcat套娃式的設(shè)計,使用模板模式,一層層的初始化 ,是不是有了更深刻的理解了呢?

load完了,接下來我們來看下start階段都干了啥事兒,繼續(xù)下一篇 ~

總結(jié)

以上是生活随笔為你收集整理的Tomcat - Tomcat 8.5.55 启动过程源码分析阶段二_load加载初始化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。