深入分析理解Tomcat體系結構-讀書筆記
Tomcat整體結構
由上圖可知Tomcat的頂層容器是Server,而且一個Tomcat對應一個Server,一個server有多個service提供服務.service包含兩個重要組件:Connector和Container.這個後面詳細講解.這個Server由誰來管理呢?當然是Catalina了,她是tomcat的管理類,她的三個方法load,start,stop分別用來管理整個服務器的生命周期.
Load方法:Load方法根據conf/server.xml文件創建Server並調用Server的init方法進行初始化.Server的init方法調用所有service的init方法,service的init方法調用所有Connector和Container的init方法.整個初始化工作就完成了.
Start方法:用於啟動服務,類似init,也是逐層進行啟動.
Stop方法:用於關閉服務,類似init,也是逐層調用關閉.
最後,CatAlina中的await方法非常重要,這個方法調用Server中的await方法,這個方法的作用就是進入一個循環,保持主線程不退出.
Tomcat組件啟動過程
Bootstrap的啟動過程
Tomcat啟動的入口方法就是Bootstrap中的main方法,代碼如下:
public static void main(String args[]) { if (daemon == null) { // Don‘t set daemon until init() has completedView CodeBootstrap bootstrap = new Bootstrap(); try {//初始化ClassLoader,創建了Catalina實例,賦值給catalinaDaemon bootstrap.init(); } catch (Throwable t) { handleThrowable(t); t.printStackTrace(); return; } daemon= bootstrap; } else { // When running as a service the call to stop will be on a new // thread so make sure the correct class loader is used to prevent // a range of class not found exceptions. Thread.currentThread().setContextClassLoader(daemon.catalinaLoader); } //根據args參數執行不同的命令 try { String command = "start";//默認執行start if (args.length > 0) { command = args[args.length - 1]; } 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); } }
public void start() throws Exception { if( catalinaDaemon==null ) init(); Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null); method.invoke(catalinaDaemon, (Object [])null); }View Code
調用執行start方法前,先判斷catalinaDaemon有沒有被初始化,如果沒有則執行init方法,然後使用Method進行反射調用Catalina的start方法.
知識點補充:
Method是java.lang.reflect包裏的類,可以使用其中的invoke方法來執行所代表的方法,invoke裏有兩個參數,第一個參數是Method方法所在的實體,第二個參數是可變參數,用於Method方法執行時所需要的參數.
Catalina的啟動過程
Catalina的啟動主要調用setAwait,load和start方法來完成.setAwait方法用於設置Server啟動後是否進入等待狀態的標誌,為true進入,否則不進入.load方法用於加載配置文件,start方法用於啟動服務器.
public void setAwait(boolean b) { await = b; } public void load() { //...創建server try { 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 a new server instance. */ public void start() { 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 { 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; } //... if (await) { await(); stop(); } }View Code
Server的啟動過程
Server接口中提供了addService(Service service),removeService(Service service)來增加和刪除Service,Server中的init和start方法循環調用Service中的init和start方法來啟動所有Service.Server的默認實現是StandardServer.
Service的啟動過程
Service的默認實現是StandardService,和StandardServer一樣也繼承自LifecycleMBeanBase類,所以init和start方法最終會調用initInternal和startInternal方法.而StandardService中的initInternal和startInternal方法主要調用container,executors,mapperListener,connectors的init和start方法.
Tomcat聲明周期管理
1.Lifecycle接口
Tomcat通過Lifecycle接口統一管理生命周期,所有生命周期組件都要實現這個接口,Lifecycle接口主要做了4件事:
1) 定義了13個String類型常量,用於LifecycleEvent事件的type屬性中,作用是為了區分組件發出LifecycleEvent事件的狀態.
2) 定義了3個管理監聽器的方法addLifecycleListener,findLifecycleListener,removeLifecycleListener,分別用來添加,查找,刪除LifecycleListener類型的監聽器.
3) 定義了4個生命周期方法:init,start,stop和destroy,用於執行生命周期的各個階段的操作.
4) 定義了獲取當前狀態的兩個方法:getState和getStateName,用來獲取當前的狀態.
具體接口代碼如下:
public interface Lifecycle { //13中LifecycleEvent事件的類型 public static final String BEFORE_INIT_EVENT = "before_init"; public static final String AFTER_INIT_EVENT = "after_init"; public static final String START_EVENT = "start"; public static final String BEFORE_START_EVENT = "before_start"; public static final String AFTER_START_EVENT = "after_start"; public static final String STOP_EVENT = "stop"; public static final String BEFORE_STOP_EVENT = "before_stop"; public static final String AFTER_STOP_EVENT = "after_stop"; public static final String AFTER_DESTROY_EVENT = "after_destroy"; public static final String BEFORE_DESTROY_EVENT = "before_destroy"; public static final String PERIODIC_EVENT = "periodic"; public static final String CONFIGURE_START_EVENT = "configure_start"; public static final String CONFIGURE_STOP_EVENT = "configure_stop"; //3個管理監聽器的方法 public void addLifecycleListener(LifecycleListener listener); public LifecycleListener[] findLifecycleListeners(); public void removeLifecycleListener(LifecycleListener listener); //4個生命周期方法 public void init() throws LifecycleException; public void start() throws LifecycleException; public void stop() throws LifecycleException; public void destroy() throws LifecycleException; //2個獲取當前狀態的方法 public LifecycleState getState(); public String getStateName(); }View Code
2.LifecycleBase
LifecycleBase是Lifecycle的默認實現,所有實現了生命周期的組件都直接或間接的繼承了LifecycleBase.LifecycleBase為Lifecycle裏的接口方法提供了默認實現.監聽器管理是專門提供了一個LifecycleSupport類來完成,在LifecycleSupport中定義了LifecycleListener類型的數組,用來保存所有監聽器,並定義了添加,刪除,查找,執行監聽器的方法;生命周期中設置了相應的狀態並調用了相應的模板方法,init,start,stop,destroy所對應的模板方法分別是initInternal,startInternal,stopInternal,destroyInternal方法,執行生命周期就是這4個方法.組件的當前狀態在這4個方法中已經設置好了,所以直接返回就OK了.
Container分析
Container是Tomcat中容器的接口,通常使用的Servlet就封裝在其子接口Wrapper中.Container一共有4個接口Engine,Host,Context,Wrapper和一個默認實現類ContainerBase,每個子接口都是一個容器,這四個容器都有一個對應的StandardXXX實現類,並且這些實現類都繼承自ContainerBase類.Container還繼承Lifecycle接口,而且ContainerBase間接繼承LifecycleBase. 4個接口Engine,Host,Context,Wrapper也符合Tomcat的生命周期管理模式.
1.Container容器結構
2.4個容器的作用
Engine:引擎,用來管理多個站點,一個Service最多只能有一個Engine.
Host:代表一個站點,也可叫虛擬主機,通過配置Host來添加站點.
Context:代表一個應用程序,對應一套程序或者WEB-INF目錄及下面的web.xml
Wraper:每個Wrapper封裝著一個Servlet.
Pipeline-value管道
Container處理請求是使用Pipeline-value管道來處理的.Pipeline-value是責任鏈模式,區別於普通的責任鏈模式:
1) 每個Pipeline都有特定的Value,而且是在管道的最後執行,這個value叫做BaseValue,是不可刪除的.
2) 在上層容器的BaseValue中會調用下層容器的管道.
Pipeline的實現方法
Pipeline管道的實現分為生命周期管理和處理請求兩部分.
1.生命周期實現方法
Container中的Pipeline在抽象實現類ContainerBase中定義,並在生命周期的startInternal,stopInternal,destroyInternal方法中調用管道的相應生命周期方法.
2.處理請求實現方法
Pipeline調用所包含Value的invoke方法來處理請求,並且在BaseValue裏又調用了子容器Pipeline所包含Value的invoke方法,直到最後調用了Wrapper的Pipeline所包含的BaseValue—StandardWrapperValue
Connector分析
Connector用於接收請求並將請求封裝成Request和Response來具體處理,最底層是使用Socket來進行連接的,Request和Response是按照Http協議來封裝的,所以Connector同時實現了TCP/IP協議和HTTP協議,Request和Response封裝完之後交給Container進行處理,Container就是Servlet容器,Container處理完成之後返回給Connector,最後Connector使用Socket將處理結果返回給客戶端,整個請求就完成了.
Connector中具體是用ProtocolHandler來處理請求,並且Connector的創建過程主要是初始化ProtocolHandler.不同的ProtocolHandler代表不同的連接類型.Http11Protocol使用的是普通的Socket來連接的.Http11NioProtocol使用的是NioSocket來連接的.
Protocol三個重要組件:
Endpoint:用於處理底層的Socket網絡連接.
Processor:用於將Enpoint接收到的請求封裝成Request
Adapter:用於將封裝好的Request交給Container處理.
最近學習有些懈怠了,主要是工作太忙,下班後基本剩下上床睡覺了.無論如何還是要不斷加強學習,提高自身技術水平.
深入分析理解Tomcat體系結構-讀書筆記