在server.xml中的<Server>標籤下看到了<Listener>子標籤,這些Listener是用來干預Tomcat加載和啓動的行爲的,既然是能夠配置的,那麼Tomcat是否提供了這種方式供開發者能夠開發自定義的邏輯來干預Tomcat喃,並且在其餘<Service><Engine>等標籤下面都可以生效喃。。。。我猜測是的,爲何喃?由於Tomcat全部核心的組件都實現了Lifecyle接口,那麼應該LifecycleListener也應該對全部接口都會有效,接下來就試着寫一段實現類來證明一下,證明以後再從源碼分析是如何讓這些Listener生效的。java
自定義LifecycleListenerapache
public class MyLifecycleListener implements LifecycleListener { @Override public void lifecycleEvent(LifecycleEvent event) { if(event.getType().equals(Lifecycle.BEFORE_INIT_EVENT)){ System.out.println("####################MyLifecycleListener output:"+Lifecycle.BEFORE_INIT_EVENT); } } }
在server.xml中<Server>標籤下添加子標籤ide
啓動看效果源碼分析
打印日誌輸出,說明添加的Listener生效了。。。那麼添加到其餘節點下是否是也會生效喃。。。答案是:<Server><Service><Engine><Connector><Context><Host>都是能夠的,可是<Valve>不行,若是非要給Valve注入,只有經過父容器的Listener繞道達到效果了。spa
既然效果看到了,那就從源碼側面分析一下是如何實現的。3d
思考一下,首先是Tomcat爲何能識別這些Listener,並且是不一樣的標籤;加載了這些Listener何時被調用。。。其實在前面的章節中已經提到了,Catalina.createStartDigester()裏面會設置不少規則,用於去匹配server.xml中的設置,就Listener而言,好比:org.apache.catalina.startup.Catalina#createStartDigester中的部分代碼調試
digester.addObjectCreate("Server/Listener", null, // MUST be specified in the element "className"); digester.addSetProperties("Server/Listener"); digester.addSetNext("Server/Listener", "addLifecycleListener", "org.apache.catalina.LifecycleListener");
這段代碼的意思就是:在解析的時候要在Server下面建立一個LifecycleListener對象,並調用addLifecycleListener方法,將對象添加到組件的lifecycleListeners集合當中。日誌
除了Server有這個配置,像下面的都有設置對應的規則,因此在解析的時候,只要他們的標籤下面子標籤設置了<Listener>,且對應的實現類是org.apache.catalina.LifecycleListener的子類便可code
就能夠。下面的列表也解釋了爲何Valve在server.xml中能夠配置,且是Lifecycle接口的子類,就算配置了Listener也不生效的緣由(由於在解析的時候匹配不到規則,不會添加)server
Server/Service/Listener Server/Service/Connector/Listener Server/Service/Engine/Listener Server/Service/Engine/Host/Listener Server/Service/Engine/Host/Context/Listener
接下來經過DEBUG證明一下,添加的Listener是否在解析完server.xml就已經實例化完,而且添加到對應的LifecycleListeners集合當中
經過上面的三張圖確實證實了以前的猜測。在解析過程當中,到底如何匹配的我就不貼出來了,感受意義不大。
而後就是來看看Listener是在何時被調用的,MyLifecycleListener裏面的判斷是事件類型爲BEFORE_INIT_EVENT,說明應該是在Catalina.load-init的時候被觸發,將斷點設置在
啓動-調試-看結果
到這裏就完全說明了自定義LifecycleListener是如何在代碼中進行加載和被調用的。
總結:
1.Tomcat源碼看到這裏,擴展點遠不及Spring那麼豐富,不過它也確實不須要那麼多擴展點,畢竟沒什麼事不會去修改Tomcat的行爲或者本身再在Tomcat的基礎上搞一個MyTomcat出來。
2.LifecycleListener和生命週期有關,感受只要是實現了Lifecycle接口的組件或者容器均可以添加LifecycleListener,但事實並非如此,好比Valve就不行。它是Tomcat提供的擴展點之一,經過此擴展點能夠往上或者往下拿到你想要的容器或者組件(DEBUG的時候看看對象的層次結構便知),對它們的狀態進行修改便可達到影響Tomcat行爲的目的。