Bootstrap是Tomcat的入口(main函數在這裏)spring
public static void main(String args[]) { if (daemon == null) { Bootstrap bootstrap = new Bootstrap(); try { //初始化ClassLoader,而且使用ClassLoader建立Catalina實例,而後 //賦值給catalinaDaemon bootstrap.init(); } catch (Throwable t) { handleThrowable(t); t.printStackTrace(); return; } daemon = bootstrap; } else { Thread.currentThread().setContextClassLoader(daemon.catalinaLoader); } try { String command = "start"; if (args.length > 0) { command = args[args.length - 1]; } /*daemon的load(),start(),setAwait()等方 法都是利用反射調用Catalina中的方法*/ if (command.equals("startd")) { args[args.length - 1] = "start"; daemon.load(args); daemon.start(); } else if (command.equals("stopd")) { args[args.length - 1] = "stop"; daemon.stop(); } else if (command.equals("start")) { daemon.setAwait(true); daemon.load(args); daemon.start(); } else if (command.equals("stop")) { daemon.stopServer(args); } else if (command.equals("configtest")) { daemon.load(args); if (null==daemon.getServer()) { System.exit(1); } System.exit(0); } else { log.warn("Bootstrap: command \"" + command + "\" does not exist."); } } catch (Throwable t) { // Unwrap the Exception for clearer error reporting if (t instanceof InvocationTargetException && t.getCause() != null) { t = t.getCause(); } handleThrowable(t); t.printStackTrace(); System.exit(1); } }
從上面的代碼中看出,Tomcat啓動代碼bootstrap
daemon.setAwait(true); daemon.load(args); daemon.start();
分別對應的Catalina的setAwait(),load(),start()方法。tomcat
public void start() { ... try { //調用Server的start()方法 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; } ... //經過setAwait(),設置await = true if (await) { await(); stop(); } }
Catalina的啓動,實際上是調用Server的Start()方法,Server的默認實現是StartardServer。服務器
繼承關係:網絡
StartardServer ==> LifecycleMBeanBase ==>LifecycleBase==>Lifecycleapp
start()方法是在LifecycleBase中ide
@Override public final synchronized void start() throws LifecycleException { ... if (state.equals(LifecycleState.NEW)) { init(); } else if (state.equals(LifecycleState.FAILED)) { stop(); } else if (!state.equals(LifecycleState.INITIALIZED) && !state.equals(LifecycleState.STOPPED)) { invalidTransition(Lifecycle.BEFORE_START_EVENT); } ... setStateInternal(LifecycleState.STARTING_PREP, null, false); startInternal(); ... }
這個類是一個模板類,在init() 中調用了initInternal(),而後啓動的時候調用startInternal(),而這2個方法是在StartardServer中實現。有點相似Spring的AbstractApplicationContext. 而後看一下StardardServer中的initInternal()和startInternal()方法,其實這2個方法就是對本身的Service進行初始化和啓動函數
protected void initInternal() throws LifecycleException { super.initInternal(); ... // Initialize our defined Services for (int i = 0; i < services.length; i++) { services[i].init(); } }
@Override protected void startInternal() throws LifecycleException { // Start our defined Services synchronized (servicesLock) { for (int i = 0; i < services.length; i++) { services[i].start(); } } }
在Catalina啓動的後,還有一個await()的方法,也是調用StandardServer的await()方法,改方法的主要做爲就是spa
@Override public void await() { if( port == -2 ) { return; } if( port==-1 ) { try { awaitThread = Thread.currentThread(); while(!stopAwait) { try { Thread.sleep( 10000 ); } catch( InterruptedException ex ) { } } } finally { awaitThread = null; } return; } ... awaitSocket = new ServerSocket(port, 1, InetAddress.getByName(address)); ··· boolean match = command.toString().equals(shutdown); if (match) { log.info(sm.getString("standardServer.shutdownViaPort")); break; } else log.warn("StandardServer.await: Invalid command '" + command.toString() + "' received");
當爲-1和-2的時候進行特殊處理,不然監聽端口(默認8005),若是收到"SHUTDOWN"消息則關閉Tomcat線程
Service的默認實現是StandardService,同時StandardService也繼承自LifecycleMBeanBase(嗯,和StandardServer同樣的生命週期管理)
@Override protected void startInternal() throws LifecycleException { ... // Start our defined Container first if (container != null) { synchronized (container) { container.start(); } } synchronized (executors) { for (Executor executor: executors) { executor.start(); } } mapperListener.start(); // Start our defined Connectors second synchronized (connectorsLock) { for (Connector connector: connectors) { if (connector.getState() != LifecycleState.FAILED) { connector.start(); } } } }
initInternal()的方式和startInternal()的方式差很少,也是調用Container、executors、mapperListener、connector的init()的方法。
能夠看出tomcat的啓動順序以下圖
Lifecycle是tomcat用於生命週期管理的接口
Lifecycle總共有13常量,用於區別13中事件,默認的實現是LifecycleBase。原理應該比較好理解,當一些事件觸發的時候,會觸發類去執行相對應的操做(例如 start的時候,會根據事件到底執行init()仍是stop())。
爲了方便擴展,咱們還能夠註冊LifecycleListener,把這些監聽器加入(addLifecycleListnener方法)監聽,當事件觸發的時候,同時還會觸發這些監聽器對應的處理。(spring boot中在啓動的時候也用到相同方法),Lifecycle的註釋中說明了哪些事件會調用哪些方法
* start() * ----------------------------- * | | * | init() | * NEW -»-- INITIALIZING | * | | | | ------------------«----------------------- * | | |auto | | | * | | \|/ start() \|/ \|/ auto auto stop() | * | | INITIALIZED --»-- STARTING_PREP --»- STARTING --»- STARTED --»--- | * | | | | | * | |destroy()| | | * | --»-----«-- ------------------------«-------------------------------- ^ * | | | | * | | \|/ auto auto start() | * | | STOPPING_PREP ----»---- STOPPING ------»----- STOPPED -----»----- * | \|/ ^ | ^ * | | stop() | | | * | | -------------------------- | | * | | | | | * | | | destroy() destroy() | | * | | FAILED ----»------ DESTROYING ---«----------------- | * | | ^ | | * | | destroy() | |auto | * | --------»----------------- \|/ | * | DESTROYED | * | | * | stop() | * ----»-----------------------------»------------------------------ *