在實(shí)踐過程中,從WebSphere中實(shí)現(xiàn)一個EJB的容器以及從WebLogic中實(shí)現(xiàn)一個JMS幾乎都是不可能的,然而來自Apache基金會的servlet容器Tomcat至少在理論上是可能做到的。
請注意,這里所說的“接口”也包含抽象類。規(guī)范的API可能會提供一個實(shí)現(xiàn)的模板,其中包括定義了一些抽象的基本類型的操作來供服務(wù)提供者去實(shí)現(xiàn)。
而服務(wù)提供者應(yīng)提供這些接口和抽象類的具體實(shí)現(xiàn)。例如,在Tomcat中HttpSession接口被以org.apache.catalina.session.StandardSession的形式實(shí)現(xiàn)。
下面讓我們來看看Tomcat容器的整體結(jié)構(gòu):
本文的目的是覆蓋這張圖中所涉及的主要請求處理組件。而上圖中的一些高級主題如集群和安全則不是在本文討論的范圍之內(nèi)。
本圖中,Service, Host, Context以及Wrapper實(shí)例之后的符號“+”表示這些對象能存在一個或多個。例如一個Service可能只有一個Engine,但是一個Engine可以包含一個或多個Host;另外,圖中旋轉(zhuǎn)的圓圈代表請求處理器的線程池。
?
1、組件分類
Tomcat架構(gòu)采用類似俄羅斯嵌套娃娃(譯注:一層套一層)的設(shè)計方式。換句話說,就是一個容器包含另一個容器,而這個被包含的容器實(shí)體反過來再包含別的實(shí)體。
而在Tomcat中,“容器”是對任何包含有其他組件的組件的通稱,如Server、Service、Engine、Host以及Context都稱為容器。 其中Server和Service組件比較特殊些,被設(shè)計為頂級元素,代表Tomcat運(yùn)行實(shí)例。而Tomcat其他所有的組件都屬于這些頂級元素。其中Engine、Host以及Contex都被官方稱為容器并依賴處理傳入請求和生成適當(dāng)數(shù)據(jù)響應(yīng)的相關(guān)組件。
而被嵌套的組件可以作為子元素來嵌入頂級元素或其他容器之中來配置這些組件的工作方式。這其中,嵌套組件包括代表可重用的工作單元的Valve組件、代表Valve鏈的Pipeline組件以及幫助特定容器建立容器管理安全的Realm組件。
此外,嵌套組件中還包括用來強(qiáng)制servlet中的類使用指定的規(guī)范來加載類的加載器;為每個web應(yīng)用提供session管理的管理器;代表web應(yīng)用中靜態(tài)資源以及提供機(jī)制來訪問這些資源的資源管理組件;以及在容器的生命周期內(nèi)允許在重要的點(diǎn)插入自定義處理程序的監(jiān)聽器組件,例如當(dāng)某個組件啟動或停止時就可以使用監(jiān)聽器。
值得注意的是,并不是所有的前臺組件都可以被嵌套在每個容器中。
這里還有最后一個主要組件,那就是連接器(Connector);它代表一個連接點(diǎn),通過這個連接點(diǎn)外部客戶端可以(比如網(wǎng)頁瀏覽器)可以連接至Tomcat容器。
在我們?nèi)W(xué)習(xí)這些組件之前,讓我們快速看下這些組件的大體結(jié)構(gòu):
請注意,上圖只展示了每個容器的關(guān)鍵屬性。
啟動Tomcat時,它運(yùn)行的Java虛擬機(jī)(JVM)實(shí)例中包含一個服務(wù)器頂級元素,該元素代表了一個完整Tomcat服務(wù)器。一個Tomcat服務(wù)器通常只包含一個Service對象,這個對象是一種包含一個或多個連接器(Connector,如HTTP、HTTPS連接器)的結(jié)構(gòu)化元素,正是這些Connector通過一個Catalina的Servlet引擎來處理傳入的請求。
引擎(Engine)表示Tomcat中處理請求的核心代碼,并且它還支持在其下定義多個虛擬主機(jī)(Host)。虛擬主機(jī)允許Tomcat引擎在將配置在一臺機(jī)器上的多個域名(如www.my-site.com、www.your-site.com)分割開來互不干擾。
反過來,每個虛擬主機(jī)又可以支持多個web應(yīng)用部署在它下邊,這就是我們所熟知的上下文對象(Context)。上下文(Context)是使用由Servlet規(guī)范中指定的Web應(yīng)用程序格式表示,不論是壓縮過的war包形式的文件還是未壓縮的目錄形式。此外,上下文一般是在web.xml文件中配置,并且該配置是根據(jù)servlet規(guī)范定義的。
從上下問角度看,在上下文中又可以部署多個servlet,并且每個servlet都會被一個包裝組件所包含。
至此,我們以上所說的Server、Service、Connector、Engine、Host、Context元素都會通過server.xml配置文件在tomcat實(shí)例中被使用。
?
2、架構(gòu)的好處
這種架構(gòu)有一些很實(shí)用的功能。它不僅便于組件的生命周期管理(每個組件管理生命周期并通知其子節(jié)點(diǎn)),而且便于在Tcomat啟動時根據(jù)從配置文件中讀取的配置文件來動態(tài)組裝出Tomcat服務(wù)器實(shí)例。尤其是server.xml在啟動時就會被解析,其內(nèi)容正是用來實(shí)例化和配置被定義的元素,并隨后組裝到正在運(yùn)行的Tomcat實(shí)例中。
server.xml文件只會被讀取一次,對server.xml的修改只有在Tomcat重啟后才會起作用。
同時這種架構(gòu)簡化配置,允許子容器繼承父容器的配置。例如Realm定義了一個可驗證權(quán)限的數(shù)據(jù)存儲,并且可以授權(quán)用戶通過web應(yīng)用來訪問受保護(hù)資源。為了便于配置,針對引擎定義的Realm適用于它所有的host和context配置。同時,某一個特定的子元素如context也可以通過繼承父類的realm來實(shí)現(xiàn)自定義realm。
?
3、頂級組件
Server和Service容器組件存在的目的是盡可能的方便結(jié)構(gòu)化。Server表示正在運(yùn)行的Tomcat實(shí)例,可包含一個或多個Service子容器;其中每個Service代表一組請求處理組件。
Server
Server代表完整的Tomcat實(shí)例在Java虛擬集中是單例,主要是用來管理容器下各個Serivce組件的生命周期。
下圖描述了Server組件的關(guān)鍵方面。如圖所示,Server實(shí)例是通過server.xml配置文件來配置的;其根元素<Server>所代表的正是Tomcat實(shí)例,默認(rèn)實(shí)現(xiàn)為org.apache.catalina.core.StandardServer。但是,你也可以通過<Server>標(biāo)簽的class屬性來自定義服務(wù)器實(shí)現(xiàn)。
服務(wù)器可重要的一方面就是它打開了8005端口(默認(rèn)端口)來監(jiān)聽關(guān)閉服務(wù)命令(默認(rèn)情況下命令為SHUTDOWN)。當(dāng)收到shutdown命令后,服務(wù)器會優(yōu)雅的關(guān)閉自己。同時出于安全考慮,發(fā)起關(guān)閉請求的連接必須來自同一臺機(jī)器上的同一個運(yùn)行中的Tomcat實(shí)例。
此外,Server還提供了一個Java命名服務(wù)和JNDI服務(wù),可以通過這兩個服務(wù)可以使用名稱來注冊專用對象(如數(shù)據(jù)源配置)。在運(yùn)行期,單個組件(如Servlet)可以使用對象名稱來通過服務(wù)器的JNDI綁定服務(wù)來查找需要的對象相關(guān)信息。
雖然JNDI實(shí)現(xiàn)并不是Servlet容器的功能,但是它屬于JavaEE規(guī)范一部分,并且可以為Servlet從應(yīng)用服務(wù)器或者servlet容器中獲取所需要的信息提供服務(wù)。
雖然在一個JVM中通常只有一個服務(wù)器實(shí)例,但是完全可以在同一臺物理機(jī)器中運(yùn)行多個服務(wù)器實(shí)例,每個實(shí)例對應(yīng)一個JVM實(shí)例;這種做法將運(yùn)行在一個JVM中的應(yīng)用中的錯誤與其他JVM中應(yīng)用的錯誤隔離開來互不影響,這也簡化了維護(hù)使得JVM的重啟與其他獨(dú)立開來。這是一個共享主機(jī)環(huán)境的機(jī)制(另一種是虛擬主機(jī)機(jī)制,很快我們將會看到),這種機(jī)制下需要將運(yùn)行在同一物理主機(jī)下的多個web應(yīng)用隔離開來。
Service
Server代表Tomcat實(shí)例本身,Service則代表Tomcat中一組請求處理的組件。
Server可以包含一個或多個Service,但每個Service則將一組Connector組件和Engine關(guān)聯(lián)了起來。
客戶端請求首先到達(dá)連接器(connector),連接器在再將這些請求輪流傳入引擎中處理,而Engine也是Tomcat中請求處理的關(guān)鍵組件。上圖中展示了HTTP連接器、HTTPS連接以及AJP組件。
一般很少會修改這個元素,而且默認(rèn)的Service實(shí)例通常就足夠使用了。
值得注意的是上圖中可能有多個Service實(shí)例。如圖所示,一個Service集中了一些連接器,每個連接器監(jiān)控一個指定的IP及端口并通過指定的協(xié)議做出響應(yīng)。所以,一個關(guān)于多個服務(wù)的使用示例就是當(dāng)你希望通過IP地址或者端口號來區(qū)分不同服務(wù)(包括這些服務(wù)中所包含的engine、host、web應(yīng)用)時。
例如,當(dāng)需要配置防火墻來為用戶開放某一個服務(wù)而該主機(jī)上托管的其他服務(wù)仍然只是對內(nèi)部用戶可見,這將確保外部用戶無法訪問內(nèi)部應(yīng)用程序,因為對應(yīng)訪問會被防火墻攔截。
因此,Service僅僅是一個分組結(jié)構(gòu),它并不包含任何其他的附加功能。
4、連接器(Connector)
Connector是客戶端連接到Tomcat容器的服務(wù)點(diǎn)它為引擎提供協(xié)議服務(wù)來將引擎與客戶端各種協(xié)議隔離開來,如HTTP、HTTPS、AJP協(xié)議。
Tomcat有兩種可配的工作模式--獨(dú)立模式或在同一web服務(wù)器中共享模式。
在獨(dú)立模式下,Tomcat會配置HTTP和HTTPS連接器,這可以使Tomcat看起來更像完整的web服務(wù)器以處理靜態(tài)請求內(nèi)容同時還委托Catalina引擎來處理動態(tài)內(nèi)容。
發(fā)布時,Tomcat為這種運(yùn)作模式提供了3種可能實(shí)現(xiàn),即HTTP、HTTP1.1以及HTTPS。
Tomcat中最常見的連接器為標(biāo)準(zhǔn)連接器,也就是通過java標(biāo)準(zhǔn)I/O實(shí)現(xiàn)的Coyote連接器。
你也許希望使用一些技術(shù)實(shí)現(xiàn),這其中就包括使用Java1.4中引入的非阻塞特性NIO,另一方面可能是通過APR充分利用本地代碼來優(yōu)化特定的操作系統(tǒng)。
值得注意的是,Connector和Engine不僅運(yùn)行在同一個JVM中,而且還運(yùn)行在同一個Tomcat服務(wù)實(shí)例中。
在共享模式中,Tomcat扮演著對web服務(wù)器如Apache httpd和微軟的IIS支撐的角色。這里web服務(wù)器充當(dāng)客戶端通過Apache模塊或者通過dll格式ISAPI模塊來和Tomcat通信。當(dāng)該模塊判定一個請求需要傳入Tomcat處理時,它將使用AJP協(xié)議來與Tomcat通信,該協(xié)議為二進(jìn)制協(xié)議,在web服務(wù)器和Tomcat通信時比基于文本的Http協(xié)議更高效。
在Tomcat端,通過AJP連接器來接收wen服務(wù)器的請求,并將請求解釋為Catalina引擎可處理的格式。
這種模式下Tomcat作為來自web服務(wù)器的單獨(dú)進(jìn)程運(yùn)行在自身獨(dú)立的JVM中。
不論在哪種模式中,Connector的基本屬性都是它所需要監(jiān)聽的IP地址及端口號,以及所支持的協(xié)議。還有一個關(guān)鍵屬性就是并發(fā)處理傳入請求的最大線程數(shù)。一旦所有的處理線程都忙,那么傳入的請求都將被忽略,直到有線程空閑為止。
默認(rèn)情況下,連接器會監(jiān)聽指定物理機(jī)器上的所有IP(address屬性默認(rèn)值為0.0.0.0);但也可以配置為只監(jiān)聽某一個IP,這將限制它只接收指定ip的連接請求。
任意一個連接器接收到的請求都會被傳入單一的服務(wù)引擎中,而這個引擎,就是眾所周知的catalina,它負(fù)責(zé)處理請求并生成響應(yīng)結(jié)果。
引擎將生成的結(jié)果返回給連接器,連接器再通過指定的協(xié)議將結(jié)果回傳至客戶端。
?
未完待續(xù)......
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
