【Tomcat8源碼學習之三】Tomcat服務啟停過程


tomcat源碼版本:apache-tomcat-8.5.54-src


一、代碼流程

1、代碼入口(運行startup.bat或startup.sh)
Bootstrap::main 

2、初始化
-->Bootstrap::init 初始化類加載器java.net.URLClassLoader
-->Bootstrap::initClassLoaders
-->Bootstrap::createClassLoader加載Tomcat公共資源lib目錄
-->讀取配置文件conf\catalina.properties屬性:common.loader="${catalina.base}/lib","${catalina.base}/lib/*.jar","${catalina.home}/lib","${catalina.home}/lib/*.jar"
如果沒有lib目錄,ClassLoaderFactory::validateFile會打印如下警告信息:
四月 16, 2020 9:35:52 上午 org.apache.catalina.startup.ClassLoaderFactory validateFile
警告: Problem with directory [E:\workspace\mot\tomcat8.5\lib], exists: [false], isDirectory: [false], canRead: [false]
四月 16, 2020 9:35:52 上午 org.apache.catalina.startup.ClassLoaderFactory validateFile
警告: Problem with directory [E:\workspace\mot\tomcat8.5\lib], exists: [false], isDirectory: [false], canRead: [false]
四月 16, 2020 9:35:52 上午 org.apache.catalina.startup.ClassLoaderFactory validateFile
警告: Problem with directory [E:\workspace\mot\tomcat8.5\lib], exists: [false], isDirectory: [false], canRead: [false]
四月 16, 2020 9:35:52 上午 org.apache.catalina.startup.ClassLoaderFactory validateFile
警告: Problem with directory [E:\workspace\mot\tomcat8.5\lib], exists: [false], isDirectory: [false], canRead: [false]

3、解析server.xml
-->Bootstrap::setAwait(true);//設置await
-->Bootstrap::load()
---->反射調用org.apache.catalina.startup.Catalina::load()加載server.xml
------>org.apache.catalina.startup.Catalina::createStartDigester設置Digester匹配模式
------>Digester.parse根據模式匹配解析server.xml,生成org.apache.catalina.core.StandardServer、org.apache.catalina.core.StandardService等server.xml配置的各個元素

4、初始化server
------>org.apache.catalina.core.StandardServer::init初始化Server
------>org.apache.catalina.util.LifecycleBase::init
server根據配置需要加載6個監聽器:
org.apache.catalina.core.NamingContextListener
org.apache.catalina.startup.VersionLoggerListener
org.apache.catalina.core.AprLifecycleListener
org.apache.catalina.core.JreMemoryLeakPreventionListener
org.apache.catalina.mbeans.GlobalResourcesLifecycleListener
org.apache.catalina.core.ThreadLocalLeakPreventionListener

其中當server處於before_init狀態時執行org.apache.catalina.startup.VersionLoggerListener::log打印tomcat版本相關信息,讀取配置文件org/apache/catalina/util/ServerInfo.properties打印tomcat版本信息:
四月 16, 2020 2:13:36 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: Server.服務器版本:     Apache Tomcat/@VERSION@
四月 16, 2020 2:13:36 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 服務器構建:            @VERSION_BUILT@
四月 16, 2020 2:13:36 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 服務器版本號(:@VERSION_NUMBER@
四月 16, 2020 2:13:36 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: OS Name:               Windows 7
四月 16, 2020 2:13:36 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: OS.版本:               6.1
四月 16, 2020 2:13:36 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 架構:                  amd64
四月 16, 2020 2:13:36 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: Java 環境變量:         C:\java\jdk1.8.0_171\jre
四月 16, 2020 2:13:36 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: JVM 版本:              1.8.0_171-b11
四月 16, 2020 2:13:36 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: JVM.供應商:            Oracle Corporation
四月 16, 2020 2:13:36 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: CATALINA_BASE:[E:\workspace\mot\tomcat8.5]
四月 16, 2020 2:13:37 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: CATALINA_HOME:         E:\workspace\mot\tomcat8.5
四月 16, 2020 2:13:37 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行參數:[-agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:57732]
四月 16, 2020 2:13:37 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行參數:[-Dmaven.multiModuleProjectDirectory=$M2_HOME]
四月 16, 2020 2:13:37 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行參數:[-Dfile.encoding=UTF-8]

需要到java path下查找libtcnative-1.dll和tcnative-1.dll,如果找不到org.apache.catalina.core.AprLifecycleListener::lifecycleEvent打印如下信息:
四月 16, 2020 2:27:21 下午 org.apache.catalina.core.AprLifecycleListener lifecycleEvent
信息: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [C:\java\jdk1.8.0_171\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:/java/jdk1.8.0_171/bin/../jre/bin/server;C:/java/jdk1.8.0_171/bin/../jre/bin;C:/java/jdk1.8.0_171/bin/../jre/lib/amd64;C:\Program Files (x86)\Common Files\NetSarang;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\TortoiseSVN\bin;C:\java\jdk1.8.0_171\bin;C:\java\jdk1.8.0_171\jre\bin;D:\apache-maven-3.6.1\bin;D:\apache-maven-3.6.1\bin;D:\Git\cmd;C:\Python27;D:\mongoDB4.0\bin;D:\mysql-5.6.45-winx64\bin;C:\erl10.5\bin;C:\RabbitMQServer\rabbitmq_server-3.7.17\sbin;D:\gradle-4.6/bin;D:\apache-ant-1.10.7/bin;C:\Users\Administrator\AppData\Local\GitHubDesktop\bin;D:\pythoneclipse;;.]

------>org.apache.catalina.core.StandardServer::initInternal
------>org.apache.catalina.util.LifecycleMBeanBase::initInternal
------>org.apache.catalina.deploy.NamingResourcesImpl::init初始化JNDI
------>org.apache.catalina.util.LifecycleBase::init
------>org.apache.catalina.deploy.NamingResourcesImpl::initInternal
------>org.apache.catalina.util.LifecycleMBeanBase::initInternal
------>org.apache.catalina.core.StandardService::init初始化Service
------>org.apache.catalina.util.LifecycleBase::init
------>org.apache.catalina.core.StandardService::initInternal
------>org.apache.catalina.util.LifecycleMBeanBase::initInternal
------>org.apache.catalina.core.StandardEngine::init初始化Engine
------>org.apache.catalina.util.LifecycleBase::init
------>org.apache.catalina.core.StandardEngine::initInternal
------>org.apache.catalina.core.StandardEngine::getRealm獲取Realm
------>org.apache.catalina.util.LifecycleMBeanBase::initInternal
------>org.apache.catalina.core.StandardThreadExecutor::init初始化線程池
------>org.apache.catalina.util.LifecycleBase::init
------>org.apache.catalina.core.StandardThreadExecutor::initInternal
------>org.apache.catalina.util.LifecycleMBeanBase::initInternal
------>org.apache.catalina.mapper.MapperListener::init初始化Mapper監聽器
------>org.apache.catalina.util.LifecycleBase::init
------>org.apache.catalina.util.LifecycleMBeanBase::initInternal
------>org.apache.catalina.connector.Connector::init初始化連接器
------>org.apache.catalina.util.LifecycleBase::init
------>org.apache.catalina.connector.Connector::initInternal
-------->org.apache.coyote.http11.Http11NioProtocol::init初始化連接協議
-------->org.apache.coyote.http11.AbstractHttp11Protocol::init
-------->org.apache.coyote.AbstractProtocol::init 會打印如下信息:
四月 16, 2020 3:08:26 下午 org.apache.coyote.AbstractProtocol init
信息: 初始化協議處理器 ["http-nio-8080"]
-------->org.apache.tomcat.util.net.NioEndpoint::init
-------->org.apache.tomcat.util.net.AbstractJsseEndpoint::init
---------->org.apache.tomcat.util.net.AbstractEndpoint::init
------------>org.apache.tomcat.util.net.NioEndpoint::bind
-------------->org.apache.tomcat.util.net.NioSelectorPool::open
--------------->org.apache.tomcat.util.net.NioSelectorPool::getSharedSelector會打印如下信息:
四月 16, 2020 3:14:37 下午 org.apache.tomcat.util.net.NioSelectorPool getSharedSelector
信息: Using a shared selector for servlet write/read
------>org.apache.catalina.util.LifecycleMBeanBase::initInternal

Catalina::load方法結束,會打印如下信息:
四月 16, 2020 2:59:23 下午 org.apache.catalina.startup.Catalina load
信息: Initialization processed in 23101 ms

5、啟動server
-->Bootstrap::start()
---->反射調用Catalina::start()
------>org.apache.catalina.core.StandardServer::start啟動Server
------>org.apache.catalina.util.LifecycleBase::start
------>org.apache.catalina.core.StandardServer::startInternal
-------->org.apache.catalina.deploy.NamingResourcesImpl::start啟動JNDI
-------->org.apache.catalina.util.LifecycleBase::start
-------->org.apache.catalina.deploy.NamingResourcesImpl::startInternal
-------->org.apache.catalina.core.StandardService::start啟動Service
-------->org.apache.catalina.util.LifecycleBase::start
-------->org.apache.catalina.core.StandardService::startInternal打印如下信息:
四月 16, 2020 3:22:09 下午 org.apache.catalina.core.StandardService startInternal
信息: Starting service [Catalina]
---------->org.apache.catalina.core.StandardEngine::start啟動Engine
---------->org.apache.catalina.util.LifecycleBase::start
---------->org.apache.catalina.core.StandardEngine::startInternal打印如下信息:
四月 16, 2020 3:22:57 下午 org.apache.catalina.core.StandardEngine startInternal
信息: Starting Servlet Engine: Apache Tomcat/@VERSION@
---------->org.apache.catalina.core.ContainerBase::startInternal
------------>org.apache.catalina.util.LifecycleBase::fireLifecycleEvent
-------------->org.apache.catalina.startup.HostConfig::lifecycleEvent
-------------->org.apache.catalina.startup.HostConfig::start
-------------->org.apache.catalina.startup.HostConfig::deployApps
---------------->org.apache.catalina.startup.HostConfig::deployDescriptors部署XML配置
---------------->org.apache.catalina.startup.HostConfig::deployWARs部署war包
---------------->org.apache.catalina.startup.HostConfig::deployDirectories部署目錄,打印如下信息:
四月 16, 2020 3:38:47 下午 org.apache.catalina.startup.HostConfig deployDirectory
信息: 把web 應用程序部署到目錄 [E:\workspace\mot\tomcat8.5\webapps\docs]
四月 16, 2020 4:08:36 下午 org.apache.catalina.startup.HostConfig deployDirectory
信息: Deployment of web application directory [E:\workspace\mot\tomcat8.5\webapps\docs] has finished in [1,018,421] ms
------------>org.apache.catalina.ha.tcp.SimpleTcpCluster::start啟動Cluster
------------>org.apache.catalina.util.LifecycleBase::start
-------------->org.apache.catalina.tribes.group.GroupChannel::start
-------------->org.apache.catalina.ha.deploy.FarmWarDeployer::start
------------>org.apache.catalina.realm.LockOutRealm::start啟動LockOutRealm
------------>org.apache.catalina.util.LifecycleBase::start
------------>org.apache.catalina.realm.LockOutRealm::startInternal
------------>org.apache.catalina.realm.CombinedRealm::startInternal
------------>org.apache.catalina.realm.RealmBase::startInternal
------------>org.apache.catalina.realm.UserDatabaseRealm::start啟動UserDatabaseRealm
------------>org.apache.catalina.util.LifecycleBase::start
------------>org.apache.catalina.realm.UserDatabaseRealm::startInternal
------------>org.apache.catalina.realm.RealmBase::startInternal
------------>org.apache.catalina.core.StandardHost::start啟動容器
------------>org.apache.catalina.util.LifecycleBase::start
------------>org.apache.catalina.core.StandardHost::startInternal
-------------->org.apache.catalina.core.StandardContext::startInternal
-------------->org.apache.jasper.servlet.JasperInitializer::onStartup
-------------->org.apache.jasper.servlet.TldScanner::scan
-------------->org.apache.jasper.servlet.TldScanner::scanJars 掃描所有部署應用下面WEB-INF下的tld文件  如果找不到就打印如下信息:
四月 16, 2020 3:57:36 下午 org.apache.jasper.servlet.TldScanner scanJars
信息: 至少有一個JAR被掃描用於TLD但尚未包含TLD。 為此記錄器啟用調試日志記錄,以獲取已掃描但未在其中找到TLD的完整JAR列表。 在掃描期間跳過不需要的JAR可以縮短啟動時間和JSP編譯時間。
---------------->org.apache.catalina.startup.HostConfig::deployDirectories部署目錄,打印如下信息:
四月 16, 2020 4:08:36 下午 org.apache.catalina.startup.HostConfig deployDirectory
信息: Deployment of web application directory [E:\workspace\mot\tomcat8.5\webapps\docs] has finished in [1,018,421] ms
------------>org.apache.catalina.core.StandardPipeline::start啟動Pipeline
------------>org.apache.catalina.util.LifecycleBase::start
------------>org.apache.catalina.core.StandardPipeline::startInternal
------------>org.apache.catalina.valves.AccessLogValve::start啟動AccessLogValve
------------>org.apache.catalina.util.LifecycleBase::start
------------>org.apache.catalina.valves.AccessLogValve::startInternal
------------>org.apache.catalina.valves.AbstractAccessLogValve::startInternal
---------->org.apache.catalina.core.StandardThreadExecutor::start啟動線程池
---------->org.apache.catalina.util.LifecycleBase::start
---------->org.apache.catalina.core.StandardThreadExecutor::startInternal
---------->org.apache.catalina.mapper.MapperListener::start啟動Mapper監聽器
---------->org.apache.catalina.util.LifecycleBase::start
---------->org.apache.catalina.mapper.MapperListener::startInternal
---------->org.apache.catalina.connector.Connector::start啟動連接器
---------->org.apache.catalina.util.LifecycleBase::start
---------->org.apache.catalina.connector.Connector::startInternal
------------>org.apache.coyote.http11.Http11NioProtocol::start啟動連接協議
------------>org.apache.coyote.AbstractProtocol::start 打印如下信息:
四月 16, 2020 4:42:15 下午 org.apache.coyote.AbstractProtocol start
信息: 開始協議處理句柄["http-nio-8080"]
------------>org.apache.tomcat.util.net.NioEndpoint::start
------------>org.apache.tomcat.util.net.AbstractEndpoint::start
------------>org.apache.tomcat.util.net.NioEndpoint::startInternal
Catalina::start方法最后打印如下信息:
四月 16, 2020 4:47:43 下午 org.apache.catalina.startup.Catalina start
信息: Server startup in 385951 ms

6、監聽停止端口
------>Catalina::await
------>org.apache.catalina.core.StandardServer::await 使用ServerSocket監聽localhost 8005端口 接收關閉指令(telnet localhost 8005 >SHUTDOWN)
StandardServer::await方法打印如下信息:
四月 16, 2020 4:49:30 下午 org.apache.catalina.core.StandardServer await
信息: A valid shutdown command was received via the shutdown port. Stopping the Server instance.

7、關閉server
------>Catalina::stop
------>org.apache.catalina.core.StandardServer::stop停止server
------>org.apache.catalina.util.LifecycleBase::stop
------>org.apache.catalina.core.StandardServer::stopInternal
-------->org.apache.catalina.core.StandardService::stop停止Service
-------->org.apache.catalina.util.LifecycleBase::stop
-------->org.apache.catalina.core.StandardService::stopInternal
四月 16, 2020 4:51:52 下午 org.apache.catalina.core.StandardService stopInternal
信息: 正在停止服務[Catalina]
-------->org.apache.catalina.connector.Connector::pause
-------->org.apache.coyote.http11.Http11NioProtocol::pause
-------->org.apache.coyote.AbstractProtocol::pause打印如下信息:
四月 16, 2020 4:51:52 下午 org.apache.coyote.AbstractProtocol pause
信息: Pausing ProtocolHandler ["http-nio-8080"]
-------->org.apache.coyote.AbstractProtocol::closeServerSocketGraceful
---------->org.apache.tomcat.util.net.NioEndpoint::closeServerSocketGraceful
-------->org.apache.catalina.core.StandardEngine::stop
-------->org.apache.catalina.util.LifecycleBase::stop
---------->org.apache.catalina.core.ContainerBase::stopInternal
-------->Pipeline::stop
-------->StandardHost::stop
-------->Realm::stop
-------->Cluster::stop
-------->StandardContext::stopInternal
-------->StandardWrapper::stopInternal
-------->StandardContext::filterStop
-------->StandardContext::listenerStop
-------->StandardContext::resourcesStop
-------->Connector::stop
-------->Connector::stopInternal
-------->org.apache.coyote.AbstractProtocol::stop會打印如下信息:
四月 16, 2020 4:51:53 下午 org.apache.coyote.AbstractProtocol stop
信息: 正在停止ProtocolHandler ["http-nio-8080"]
-------->MapperListener::stop
-------->StandardThreadExecutor::stop
-------->NamingResourcesImpl::stop

8、銷毀server
------>org.apache.catalina.core.StandardServer::destroy銷毀server
------>StandardService::destroy
-------->org.apache.coyote.AbstractProtocol::destroy
-------->org.apache.catalina.connector.Connector::destroyInternal
-------->org.apache.coyote.AbstractProtocol::destroy會打印如下信息:
四月 16, 2020 5:01:37 下午 org.apache.coyote.AbstractProtocol destroy
信息: 正在摧毀協議處理器 ["http-nio-8080"]
-------->org.apache.catalina.core.StandardEngine::destroy
-------->org.apache.catalina.core.ContainerBase::destroyInternal
------>NamingResourcesImpl::destroy

 load:

initialize:

start:

deploy APP:

二、啟停關鍵組件

1、啟停腳本
startup.bat、startup.sh、shutdown.bat、shutdown.sh內部調用catalina.bat或者catalina.sh,catalina.bat或者catalina.sh內部調用org.apache.catalina.startup.Bootstrap,並傳入相應的參數;或者直接運行catalina.bat或者catalina.sh加入我們需要的參數

2、org.apache.catalina.startup.Bootstrap啟動器
2.1 設置catalina.home和catalina.base目錄
2.2 接收運行參數
2.3 init()
--initClassLoaders()創建三個類加載器:commonLoader、catalinaLoader、sharedLoader,默認都是URLClassLoader
--反射調用org.apache.catalina.startup.Catalina::setParentClassLoader設置其父加載器為sharedLoader
2.4 反射調用org.apache.catalina.startup.Catalina::setAwait、load、start、stop、stopServer方法

3、org.apache.catalina.startup.Catalina-實際server啟動者
3.1 setAwait():設置監聽終止server指令的端口
3.2 load():
--initDirs();初始化系統默認的臨時文件目錄
--initNaming();在創建Digester匹配模式之前初始化JNDI服務
--createStartDigester()創建啟動Digester匹配模式
--digester.push(this);將org.apache.catalina.startup.Catalina作為第一個元素
--digester.parse(inputSource);解析Server.xml
--org.apache.catalina.core.StandardServer.setCatalina(this);
--org.apache.catalina.core.StandardServer.setCatalinaHome(Bootstrap.getCatalinaHomeFile());設置catalina.home
--org.apache.catalina.core.StandardServer.setCatalinaBase(Bootstrap.getCatalinaBaseFile());設置catalina.base
--initStreams();重定向System.out and System.err 使用自定義的流
--org.apache.catalina.core.StandardServer.init()初始化server

3.3 start() --org.apache.catalina.core.StandardServer.start() --await()阻塞監聽 --stop()當監聽到關閉命令進行關閉 3.4 stop() --org.apache.catalina.core.StandardServer.stop();停止server --org.apache.catalina.core.StandardServer.destroy();銷毀server 3.5 stopServer()終止server --createStopDigester():創建終止Digester匹配模式 --org.apache.catalina.core.StandardServer.stop();停止server --org.apache.catalina.core.StandardServer.destroy();銷毀server

 三、關閉鈎子

對java而言,虛擬機會對以下幾種操作進行關閉:
(1)系統調用System.exit()方法;
(2)程序最后一個守護線程退出時,應用程序正常退出;
(3)用戶強行中斷程序運行,比如ctrl+c等其他方式中斷java程序;

關閉鈎子是一個特殊的線程,可以人為編碼實現。java進程在停止之前,會調用已注冊關閉鈎子的run()方法。
關閉鈎子的生成:
1.創建Thread的子類;
2.重寫run方法,應用程序關閉時會調用該方法,不需要調用start方法;
3.在應用中實例化關閉鈎子類;
4.使用Runtime注冊關閉鈎子:Runtime.getRuntime().addShutdownHook(shutdownHook);

tomcat關閉鈎子舉例:

public class Catalina {
    ....
    //默認使用關閉鈎子
    protected boolean useShutdownHook = true;
    protected Thread shutdownHook = null;
    
    public void start() {
        ....        
        if (useShutdownHook) {
            if (shutdownHook == null) {
                shutdownHook = new CatalinaShutdownHook(); } Runtime.getRuntime().addShutdownHook(shutdownHook);
            LogManager logManager = LogManager.getLogManager();
            if (logManager instanceof ClassLoaderLogManager) {
                ((ClassLoaderLogManager) logManager).setUseShutdownHook(false);
            }
        }
        ....
    }
    
    protected class CatalinaShutdownHook extends Thread {

        @Override
        public void run() {
            try {
                if (getServer() != null) {
                    Catalina.this.stop();
                }
            } catch (Throwable ex) {
                ExceptionUtils.handleThrowable(ex);
                log.error(sm.getString("catalina.shutdownHookFail"), ex);
            } finally {
                // If JULI is used, shut JULI down *after* the server shuts down
                // so log messages aren't lost
                LogManager logManager = LogManager.getLogManager();
                if (logManager instanceof ClassLoaderLogManager) {
                    ((ClassLoaderLogManager) logManager).shutdown();
                }
            }
        }
    }
    ......
}

 

參考:
Tomcat源碼分析(一)--服務啟動


免責聲明!

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



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