其中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函數會實例化出來一個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); } }
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有四種容器,這個經過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的啓動的概要流程圖能夠表示以下: