程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> How Tomcat works — 四、tomcat啟動(3),tomcatworks

How Tomcat works — 四、tomcat啟動(3),tomcatworks

編輯:JAVA綜合教程

How Tomcat works — 四、tomcat啟動(3),tomcatworks


上一節說到StandardService負責啟動其子組件:container和connector,不過注意,是有先後順序的,先啟動container,再啟動connector,這一節先來看看container。

目錄

  • Pipeline和Vavle
  • StandardEngine類和StandardHost類
  • StandardContext類
  • 總結

Pipeline和Vavle

在第二節(How Tomcat works — 二、tomcat啟動(1))中沒有介紹關於Pipeline和Vavle,因為前面側重的是整個架構,但是在初始化的時候就不得不說了。

Pipeline,就是一根管道,用來連接兩個容器,在一個容器流向下一個容器的時候使用。在tomcat中也是這個意思,很形象,Engine、Host等都是容器,在執行完上一個容器(比如Engine)的相關操作的時候要開始執行下一個容器(比如Host)的操作了,這個時候需要經過一根管道pipeline,那麼我們可以在管道中執行一個其他必要的操作,這個時候可以在管道上面添加Vavle(閥),一根管道pipeline上可以有多個閥門(也很形象)。每根管道都有一個默認的閥門。

在tomcat實現中有一個實現了Pipeline接口的類StandardPipeline——是每兩個容器之間的管道,每個容器都有一個默認的Valve實現StandardEnginevavle、StandardHostValve、StandardContextVavle、StandardWrapperVavle。

其實valve的作用和filter的作用類似。

StandardEngine類

StandardEngine作為整個容器的最頂層負責啟動其子組件——StandardHost,對,他就這一個作用。

StandardEngine.initInternal

這個方法被超類LifecycleBase.init方法調用,主要作用就是調用超類LifecycleMBeanBase.initInternal方法注冊MBean,並初始化一個startStopExecutor(ThreadPoolExecutor),後面用來使用線程啟動子容器。

StandardEngine.startInternal

這個方法的主要作用就是調用父類的方法Container.startInternal——主要的操作就在這個方法裡面:

protected synchronized void startInternal() throws LifecycleException { // Start our subordinate components, if any if ((loader != null) && (loader instanceof Lifecycle)) ((Lifecycle) loader).start(); logger = null; getLogger(); if ((manager != null) && (manager instanceof Lifecycle)) ((Lifecycle) manager).start(); if ((cluster != null) && (cluster instanceof Lifecycle)) ((Lifecycle) cluster).start(); Realm realm = getRealmInternal(); if ((realm != null) && (realm instanceof Lifecycle)) ((Lifecycle) realm).start(); if ((resources != null) && (resources instanceof Lifecycle)) ((Lifecycle) resources).start(); // Start our child containers, if any Container children[] = findChildren(); List<Future<Void>> results = new ArrayList<Future<Void>>(); for (int i = 0; i < children.length; i++) { results.add(startStopExecutor.submit(new StartChild(children[i]))); } boolean fail = false; for (Future<Void> result : results) { try { result.get(); } catch (Exception e) { log.error(sm.getString("containerBase.threadedStartFailed"), e); fail = true; } } if (fail) { throw new LifecycleException( sm.getString("containerBase.threadedStartFailed")); } // Start the Valves in our pipeline (including the basic), if any if (pipeline instanceof Lifecycle) ((Lifecycle) pipeline).start(); setState(LifecycleState.STARTING); // Start our thread threadStart(); } View Code
  • manager、cluster、realm、resource如果有的話全部啟動(所以其實tomcat本身就是支持集群的)
  • 調用findChildren方法找到左右子容器——也就是所有的StandardHost(默認只有一個)
  • 對於每個子容器(StandardHost)使用線程啟動,StartChild類實現了Callable接口,在call方法裡面執行傳入容器的start方法,將子容器啟動作為一個task,然後使用ThreadPoolExecutor.submit提交task
  • 然後等待這些Future執行完(因為裡面是各個子容器的初始化和啟動工作,後面connector必須在容器准備好之後才能啟動)
  • 啟動pipeline(這裡就是StandardPipeline),pipeline會啟動所包含的所有vavle(這裡就是只有StandardEngineValve)
  • setState會通知所有監聽了StandardEngine事件的listener
  • threadStart,啟動一個後台線程執行包含的所有閥門的backgroundProcess方法,並觸發Lifecycle.PERIODIC_EVENT事件

StandardHost類

StandardHost的作用和StandardEngine類似,都是初始化啟動子容器,不過這裡是StandardContext。啟動的方式也一樣,所以就不再詳述。

StandardContext類

這個類才是重中之重,解析web.xml、部署webapp都在這兒實現。在StandardHost中調用StandardContext.start方法,執行的是超類LifecycleBase.start方法,主要進行了如下操作

  • 調用init方法初始化StandardContext
  • 調用startInternal方法啟動StandardContext

init

在該方法中主要進行了MBean的注冊,再就是觸發了Lifecycle.AFTER_INITEVENT事件,ContextConfig是StandardContext的listener,在發生該事件的時候執行ContextConfig.init方法,在該方法中主要是構造一個能解析web.xml的digester。

startInternal

由於LifecycleBase沒有實現該方法,所以就是直接調用StandardContext.startInternal,在StandardContext.startInternal方法中主要進行了如下操作:

  • setResource:添加新的resource
  • 如果webappLoader為null則初始化
  • 初始化charset mapper
  • 設置webapp工作目錄,比如%TOMCAT_HOME%/work//Catalina/localhost/_等
  • 觸發Lifecycle.CONFIGURE_START_EVENT事件,ContextConfig監聽了該事件,會進行解析web.xml
  • 啟動所有的children(StandardWrapper,代表所有配置的servlet)
  • 初始化Standardmanager
  • 配置initParam
  • 配置啟動filter、listener

 

總結

container部分終於啟動完成了,不過還是有些部分略過了,比如StandardWrapper(這個還可以往深挖,不過也包含在StandardContext的啟動過程中)初始化和webapp的發布。到現在發現,這些啟動過程就是圍繞生命周期的這幾個方法展開:

  • start和init:LifecycleBase提供了默認實現
  • startInternal和initInternal:這兩個方法每個類都是重載實現自己需要啟動的東西

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved