tomcat容器啓動

tomcat文件結構

其中conf中有一些比較重要的文件,以下:java

catalina.properties Tomcat環境變量配置
catalina.policy 安全模式下運行時的默認安全策略
context.xml 全部web應用須要加載的Context配置,若是用戶指定了本身的Context,這個文件將會被覆蓋
logging.properties Tomcat日誌文件,能夠修改tomcat的日誌級別
Server.xml Tomcat的很很重要的配置文件,配置鏈接器,監聽端口,服務器實例等,tomcat優化相關也均會配置在此文件中
tomcat-users.xml Tomcat manager認證
web.xml Tomcat默認的web.xml文件,定義了基礎的Servlet和MIME映射。若是應用中沒有web.xml,則tomcat會使用此文件做爲默認文件

啓動腳本

當咱們下載下來tomcat之後,在bin文件夾下,tomcat分別提供了linux和windows的啓動腳本文件,startup.bat和startup.sh,這個文件沒有實質性的用處,主要是爲了引導執行catalina.sh(或者catalina.bat)文件,因此咱們在啓動tomcat時,也能夠直接啓動catalina.sh。這個文件內容特別多,有500多行,是tomcat啓動的核心文件。主要分爲如下幾方面內容linux

1.   設置CATALINA_HOME和CATALINA_BASEweb

2.   尋找是否有setevn.sh和setclasspath.sh文件,並加載,咱們自定義的tomcat參數,例如設置jvm參數的大小,就能夠在新建一個setevn.sh文件,而後在這個文件中配置,tomcat會自動加載這個文件。setclasspath.sh是一些必要的批處理腳本,它只負責查找和檢查JAVA_HOME和JRE_HOME兩個環境變量。apache

3.   設置日誌組件。windows

4.   根據不一樣的配置組裝最後要啓動的命令參數。設計模式

5.   執行啓動命令tomcat

 啓動類

 tomcat的啓動類是Bootstrap.java,類首先經過靜態方法加載catalina.base和catalina.home的位置,而後實例化Bootstarp類,經過調用init方法進行初始化。初始化時,加載安全

${catalina.base}/lib,${catalina.base}/lib/*.jar,"${catalina.home}/lib,${catalina.home}/lib/*.jar 這些文件夾以及jar文件。並建立tomcat原始的ClassLoader。而後經過classLoader實例化org.apache.catalina.startup.Catalina類並進行初始化其parentClassLoader,而後此函數線程做爲守護線程。服務器

默認的啓動參數是start,當參數是start時表明是啓動tomcat,其實是調用Catalina.java的load()和start()函數進行啓動。接下來分別看一下這兩個函數框架

load()函數

load函數會實例化出來一個Server實例。每一個tomcat只能有一個server實例。server節點是server.xml的根節點,tomcat全部的配置也都是在這這個節點之下,下屬節點主要分爲鏈接器,監聽器,容器這幾類。

public void load() {

        long t1 = System.nanoTime();
		//設置臨時文件目錄
        initDirs();
		
        // 初始化digester框架可能用的一些naming信息
        initNaming(); 

        // 建立Digester對象,而且作節點和相關實體類的映射對照關係
        Digester digester = createStartDigester();

        InputSource inputSource = null;
        InputStream inputStream = null;
        File file = null;
        try {
			
            	//巴拉巴拉一大堆,就是爲了加載server.xml文件到digester中
            }

            try {
                inputSource.setByteStream(inputStream);
                digester.push(this);
                digester.parse(inputSource);
            } catch (SAXParseException spe) {
               
            }
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    // Ignore
                }
            }
        }
		
	 
	/**
初始化Server的一些最基本的信息
 server指的是org.apache.catalina.Server,這個也就是tomcat的頂級容器
	**/
        getServer().setCatalina(this);
        getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
        getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());

        // Stream redirection
        initStreams();
        try {
        	/**
        	 * 初始化Server信息,Server是一個接口,默認實現是StandardServer
        	 * StandardServer繼承自抽象類LifecycleBase,init方法由其實現,tomcat的容器的默認實現均繼承自此抽象類,而且實現lifecycle接口,LifecycleBase中有抽象方法startInternal()由其子類進行實現
        	 * 具體的針對tomcat容器的啓動方式稍後再作分析
        	 */
            getServer().init();
        } catch (LifecycleException e) {
            if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
                throw new java.lang.Error(e);
            } else {
                log.error("Catalina.start", e);
            }
        }

start函數

public void start() {
    	
    	//重複的加載server,以保證server不是空的,重複加載之後若是server依然爲空,則拋出異常,啓動失敗
        if (getServer() == null) {
            load();
        }
        if (getServer() == null) {
            log.fatal("Cannot start server. Server instance is not configured.");
            return;
        }

        long t1 = System.nanoTime();

        // Start the new server
        try {
        	//啓動server容器
            getServer().start();
        } catch (LifecycleException e) {
            log.fatal(sm.getString("catalina.serverStartFail"), e);
            try {
                getServer().destroy();
            } catch (LifecycleException e1) {
                log.debug("destroy() failed for failed Server ", e1);
            }
            return;
        }

        long t2 = System.nanoTime();
        if(log.isInfoEnabled()) {
            log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms");
        }

        // Register shutdown hook
        if (useShutdownHook) {
            if (shutdownHook == null) {
                shutdownHook = new CatalinaShutdownHook();
            }
            //增長關閉鉤子,tomcat在關閉(無論是正常仍是異常)時執行後續的收尾工做
            Runtime.getRuntime().addShutdownHook(shutdownHook);

            // If JULI is being used, disable JULI's shutdown hook since
            // shutdown hooks run in parallel and log messages may be lost
            // if JULI's hook completes before the CatalinaShutdownHook()
            LogManager logManager = LogManager.getLogManager();
            if (logManager instanceof ClassLoaderLogManager) {
                ((ClassLoaderLogManager) logManager).setUseShutdownHook(
                        false);
            }
        }
        if (await) {
        	//開啓ServerSocket,等待請求,並接收請求
            await();
            //去除關閉鉤子,逐級關閉容器
            stop();
        }
    }

tomcat的容器以及啓動

tomcat有四種容器,這個經過server.xml能夠看出來

容器均實現Lifecycle接口,它的啓動,是在經過調用StandardServer load方法時進行初始化,經過調用start方法進行啓動。在Lifecycle的開頭註釋部分,很是明確的畫出了整個容器的聲明週期過程。

首先容器須要先調用init()方法進行初始化,初始化完成以後調用start()方法啓動容器,當容器再也不使用,調用stop()進行中止, 最後destory()方法銷燬容器

在啓動的過程當中,因爲涉及到不少的事件,對於各類事件的處理不可能硬編碼到代碼中,而且了爲了可擴展,lifecycle定義了不少的事件監聽點,用到自定義實現的觀察者設計模式。各個事件的監聽器能夠註冊本身感興趣的事件,當這事件發生時會進行通知。

生命週期時期

調用事件

init

在init以前會調用先後會分別調用註冊瞭如下事件的方法

BEFORE_INIT_EVENT

AFTER_INIT_EVENT

start

在接收到start命令時,調用START_EVENT

Start以前調用BEFORE_START_EVENT,容器啓動以後調用註冊了AFTER_START_EVENT事件的方法。

stop

接收到stop命令,會調用STOP_EVENT的事件,

Stop以前調用BEFORE_STOP_EVENT,以後調用AFTER_STOP_EVENT

destroy

容器銷燬以前調用AFTER_DESTROY_EVENT,銷燬以後調用感興趣的註冊了BEFORE_DESTROY_EVENT事件的類的方法

除了以上還提供了PERIODIC_EVENT事件,這個註冊此時間的方法會被週期性的執行,配合CONFIGURE_START_EVENT和CONFIGURE_STOP_EVENT事件的使用,能夠監控配置文件是否修改,而後進行熱部署的效果。

 

tomcat容器的啓動採用的是鏈式啓動結構,有父容器進行查找其下面的字容器進行啓動。例如咱們啓動Engine,它會自動的找它下面的Host,啓動Engine的同時進行啓動host。

容器均實現Container接口, ContainerBase,以Standardxxx開頭的類是容器的默認實現,Container接口中有一個findChinldren()方法,用來查找這個容器下的子容器,默認由ContainerBase實現,container接口有一個默認的抽象實現類ContainerBase實現,而findChinldren()方法也默認由其實現。容器的默認實現Standardxxx 繼承自ContainerBase。

 

而整個tomcat的啓動的概要流程圖能夠表示以下:

相關文章
相關標籤/搜索