Tomcat容器到底是什么
學java有一小段時間了,一直使用Tomcat,也知道Tomcat是一個大的Servlet容器,里面還有許多子容器,容器之間都是相互嵌套的。也看過一下接收Tomcat的文章,都是一幅圖,圖中有好多個框框相互嵌套,表示容器與容器之間的相互嵌套,也沒什么說明,把我看得雲里霧里的。所以要想了解的更多必須自己探索一下。
現在把自己學到的一點點知識記下來,以免忘記了。
都說Tomcat是一個容器,那么這個容器到底是什么東西,因為說它是一個容器我還是覺得有點抽象,而我看了很多文章都沒看到有人說。所以,我想知道Tomcat的本質。腦袋有點轉不過彎來,寫到這里才發現既然Tomcat是用java寫的那它的容器的本質應該就是java類啦。
在開始探索之前我就知道Tomcat中有Server、Service、Engine、Host.....等容器。這些容器與容器之間相互嵌套。既然這些容器的本質就是實實在在的java類(容器就是java類,已經夠具體了,這樣我才能理解,因為我天天寫java類 ^v^ ),那這些不同的容器分別使用什么樣的java類來描述的呢???我點是我想要知道的。
經過一番探索,知道這些容器都是有生命周期的java類,他們都繼承了共同的接口 Lifecycle 。所以Lifecycle就是這些容器這些java類的頂層接口了。下面是我畫的繼承體系圖。
圖一:圖片保存下來看吧,博客園的圖片編輯無語,改天好好研究一下怎么讓他彈出來再改。
通過圖中的類名就可以知道哪些類是表示Server,哪些是表示Service哪些是。。。。。。
Tomcat中的這些容器都是有生命周期的容器,那么它的類肯定就有聲明周期方法了。先看看頂層接口 Lifecycle ,這個接口里面主要定義了一些生命周期的方法。所以,繼承自這個接口的所有容器都有生命周期。
圖二:
init()方法:初始化容器組件,它必須在啟動容器之前調用。它會創建許多對象。
start():啟動容器,比如啟動一個Server。
stop():停止執行
destroy():銷毀這個容器。
Server容器:一個StandardServer類實例就表示一個Server容器
Service容器:一個StandardService類實例就表示一個Service容器
Engine容器:一個StandardEngine類實例就表示一個Engine容器。
Host容器:一個StandardHost類實例就表示一個Host容器。
Context容器:一個StandardContext類實例就表示一個Context容器。
Wrapper容器:一個StandardWrapper類實例就表示一個Wrapper容器。
以上一共有六種類型的容器,從上到下嵌套,也就是Server容器里面有Service容器,Service容器里面有Engine容器。。。。。。這就是這些容器之間的嵌套關系。
需要注意的是,這些容器之間存在父子關系,但是他們對應的java類之間卻不是父子關系。由圖一可以看出來。
父容器與子容器之間的數量關系
這些父容器和子容器之間有什么樣的數量關系呢???
一個Server容器可以有多個Service容器
/** * The set of Services associated with this Server.用一個數組來保存子容器的引用 */ private Service services[] = new Service[0];
一個Service容器只可以有一個子容器。
/** * The Container associated with this Service. (In the case of the * org.apache.catalina.startup.Embedded subclass, this holds the most * recently added Engine.)
它不是用一個數組來保存子容器的引用的。所以直接的子容器只有一個。 */ protected Container container = null;
這里用Container來表示子容器,根據圖一可以看出,Container是Engine、Host、Context、Wrapper 接口的父接口,所以Service容器下面的子容器可能是Engine、Host、Context、Wrapper。但是我覺得一般情況下Service的子容器都是Engine容器吧。
一個Engine容器里面可以有多個 Host 容器
/** * Add a child Container, only if the proposed child is an implementation * of Host. * * @param child Child container to be added */ @Override public void addChild(Container child) { if (!(child instanceof Host))//這里說明Engine的子容器只能是Host throw new IllegalArgumentException (sm.getString("standardEngine.notHost")); super.addChild(child); }
一個Host容器里可以有多個 Context 容器。
/** * Add a child Container, only if the proposed child is an implementation * of Context. * * @param child Child container to be added */ @Override public void addChild(Container child) { child.addLifecycleListener(new MemoryLeakTrackingListener()); if (!(child instanceof Context))//這里說明Host容器的子容器只能是Context容器 throw new IllegalArgumentException (sm.getString("standardHost.notContext")); super.addChild(child); }
一個Host容器中可以有多個Wrapper容器。
/** * Add a child Container, only if the proposed child is an implementation * of Wrapper. * * @param child Child container to be added * * @exception IllegalArgumentException if the proposed container is * not an implementation of Wrapper */ @Override public void addChild(Container child) { // Global JspServlet Wrapper oldJspServlet = null; if (!(child instanceof Wrapper)) {//這里說明Context容器的子容器只能是Wrapper容器。 throw new IllegalArgumentException (sm.getString("standardContext.notWrapper")); } //這里刪除了部分代碼 }
Wrapper容器下面不允許再有子容器。Wrapper容器是最底層的容器。如果添加子容器的話會拋出異常。
/** * Refuse to add a child Container, because Wrappers are the lowest level * of the Container hierarchy. * * @param child Child container to be added */ @Override public void addChild(Container child) { throw new IllegalStateException (sm.getString("standardWrapper.notChild")); }
服務器接收到請求信息后如何傳到我們編寫的HttpServlet的呢??如果是SpringMVC的話會先到DispatcherServlet再到Controller,而DispatcherServlet也是HttpServlet的一個間接子類。在下一篇文章Tomcat是如何將請求一步步傳遞到我們編寫的HttpServlet類中的