嵌套組件
這些組件是針對Tocmat做的特定實現,他們的主要目的是使各種Tomcat容器可以完成各自的工作。
1、閥(Valve)
valve是處理元素,它可以被包含在每個Tomcat容器的處理路徑中--如engine、host、context以及servelt包裝器。若要增加Valve到Tomcat容器則需要在server.xml中使用<Valve>標簽。在server.xml中這些標簽的執行順序與其物理順序相同。
而在Tomcat中也分布這大量預先編譯好的valve。包括:
? 在請求日志元素中將請求(如遠程客戶端ip地址)寫入日志文件或數據庫時
? 根據遠程客戶端ip或主機名來控制某一特定web應用的訪問權限時
? 記錄每個請求和響應頭信息日志時
? 在同一個虛擬主機下為多個應用配置單點登錄時
如果以上這些都不能滿足你的要求,那么你可以通過繼承org.apache.catalina.Valve來實現自定義的Valve并將其配置到對應服務中。
但是對于一個容器來說,它并不會持有某個單獨valve的引用;相反,它會持有一個稱作管道(Pipeline)的單一實體的引用,并用這個管道來表示與該容器所關聯的一系列valve。
當一個容器被調用來處理一個請求時,它會委托與其關聯的管道來處理對應請求。
在管道中,這些valve則是基于他們在server.xml中的定義作順序排列。其中排在隊列中排在最后的valve被稱為管道的基本valve,該valve用來完成去執行容器的核心功能的任務。
與單個valve不同,管道在server . xml不是一個明確的元素,而是含蓄的按照valve在給定容器中所定義的順序組成。
并且在管道中,每個valve都知道其下一個valve;在它執行完前置處理以后,接下來它會調用鏈中的下一個valve,當該調用返回以后,它會在return之前執行他自身的處理任務。
這種方式和servlet規范中的過濾器鏈所做的事情非常相似。
在這幅圖中,當接收到傳入請求時引擎所配置的valve首先被觸發。其中引擎中基本的valve負責確定目標主機委托該主機來處理;接下來目標主機(www.host1.com)的valve被按順序觸發。而該主機的基本valve則又決定了目標context(在這里是Context1)并且委托該context來處理該請求。最后Context1中所配置的valve被觸發,然后通過context中配置的基本valve委托給適當的包裝器來處理;而包裝器的基本valve又將處理轉交至被包裝的servlet來處理。
處理完成以后,響應結果會按照以上的路徑反方向返回。
由于Valve就成了Tomcat服務器實現中的一部分,并且可以為開發者提供一種方式將自定義的代碼注入到處理請求的servlet容器中。因此,自定的valve類文件需要發布到CATALINA_HOME/lib目錄下而不是應用的發布目錄WEB-INF/classes。
由于它們并不是servlet規范中的部分,所以valve在企業級一用中屬于不可移植元素。因此,如果已經依賴了一個特定的valve時,你必須在不同的應用服務器上找到對等的選擇方案。
還有很重要的一點就是,為了不影響請求處理的效率必須要保證valve的代碼高效執行。
2、Realm
容器管理安全方面的工作通過容器處理應用程序的身份驗證和授權方面來解決。
身份驗證存在的主要任務就是確保用戶所說的就是她自己,而授權的主要任務是決定一個用戶是否可以在某個應用下執行特定操作。
由容器來管理安全的優勢是可以通過應用的發布者直接來配置安全措施。也就是說,為用戶分配密碼以及為用戶分配角色都可以用戶配置來完成,而這些配置也可以在修改任何代碼的情況下來供多個web應用共用。
應用管理安全
還有一種可選方案就是通過應用來管理安全問題。這種情況下,我的web應用程序代碼就是唯一的仲裁者來決定用戶在我們的應用下是否有訪問特定功能或資源的權限。
想要使容器來管理安全問題起作用,我們需要組裝一下組件:
? 安全約束:在我們的web應用部署描述器web.xml中,我們必須確定限制資源訪問的url表達式以及可以訪問這些資源的用戶角色。
? 憑證輸入機制:在web.xml部署文件中,我們需要指定容器應該如何提示用戶通過憑證來驗證。這通常是通過彈出一個對話框提示用戶輸入用戶名和密碼來完成,但也可以配置使用其他機制,如一個定制的登錄表單等。
? Realm:這是一個數據存儲機制來保存用戶名、密碼以及角色來對用戶所提供的憑證信息進行檢查。它可以是一個簡單的xml文件,一個通過JDBC API來訪問的關系型數據庫中的一張表或者是可以通過JNDI API訪問的輕量級目錄訪問協議服務器(LDAP)。正是Realm為Tomcat提供了一致的訪問機制來訪問這些不同的數據源。
以上這三種組件在技術上是相互獨立的。基于容器安全的威力就在于我們可以根據我們自身的安全情況從這幾種方式中選出適合的一種或幾種方式來混合使用。
至此,當一個用戶請求一個資源時,Tomcat將檢查對所請求的資源是否已經存在了安全限制。對于存在限制的資源,Tomcat將自動要求用戶提供身份憑證并通過所配置的Realm來檢查用戶所提供憑證是否符合。只有在用戶所提供的憑證信息通過了驗證或者用戶的角色在可訪問資源的配置之列才能訪問對應資源。
3、執行器
這是從tomcat 6.0.11版本開始,新增的一個組件。此組件允許您配置一個共享的線程池,以供您的連接器使用。您的連接器可能使并發線程的數量達到上限。請注意,此限制同樣適用于:即使一個特定的連接器沒有用完為它配置的所有線程。
4、監聽器
每個主要的tomcat組件都實現了org.apache.catalina.Lifecycle接口。實現了該接口的組件注冊到監聽器,然后該組件的生命周期事件被觸發,比如該組件的啟動和停止都會被監聽。一個監聽器實現了org.apache.catalina.LifecycleListener接口,也實現了該接口的lifecycleEvent()方法,監聽器捕捉到一個LifecycleEvent 表示事件已經發生。這就給您提供了一個機會:把您自定義的進程注入到tomcat的生命周期。
5、會話管理器
會話讓使用無狀態HTTP協議的應用程序完成通信。會話表示客戶端和服務器之間的通信,會話功能是由javax.servlet.http.HttpSession 的實例實現的,該實例存儲在服務器上而且與一個唯一的標識符相關聯,客戶端在與服務器的每次交互中根據請求中的標識符找到它的會話。一個新的會話在客戶端請求后被創建,會話一直有效直到一段時間后客戶端連接超時,或者會話直接失效例如客戶退出訪問服務器。
?
上圖顯示了一個非常簡單的 tomcat 會話機制視圖。Catalina 引擎(engine)使用了組件org.apache.catalina.Manager 去創建、查找、注銷會話。該組件負責管理為上下文創建的會話以及會話的生命周期。會話管理器(Manager)把會話存放在內存中,但是它支持在服務器重啟時恢復會話。當服務器停止時,會話管理器把所有活動的會話寫入磁盤,當服務器重新啟動時把會話重新加載到內存。
一個<Manager>必須是 <Context>的子節點,而且<Manager>負責管理與web應用程序上下文相關的會話。
會話管理器管理這樣的屬性:例如用來生成會話標識符的算法,每秒鐘檢查過期會話的頻率,支持的活動會話的最大數目,以及持久化會話的文件。
會話管理器實現了這樣的功能:為會話提供持久化存儲,例如一個文件或一個JDBC數據庫。
6、加載器
這個組件是一個給定的web應用程序的類加載器。Java中的類加載器是一個神秘的實體。簡而言之,類加載器負責加載、解釋Java類編譯后的字節碼。
一個Java類的字節碼可能存放在各種不同的位置,最常見的是在本地文件系統或網絡中。類加載器的主要任務是:抽象字節如何被獲取以及如何重組到內存中的類的過程。
7、委托(代理)模型
自從Java 2以來,類加載機制使用了委托模型,JVM中的類加載器被組織成了父---子層次結構。據介紹,每個類加載器首先把查找和加載一個類的任務委托給它的父級,在它自己嘗試做這個任務之前。
這種委托機制確保:沒有應用程序可以加載一個有惡意的系統類(例如java.lang.Object),它可能危及在JVM中運行的應用程序的完整性。
類加載器層次結構的頂層是Bootstrap 類加載器,它也叫原始類加載器,它是原生代碼而且是JVM的一部分。作為JVM的一部分可以保證:至少有一個可以依靠的類加載器,去加載Java的核心類(例如java.lang.Object)。這個類加載器(Bootstrap )負責從Java核心包(例如java.lang 或 java.util)里加載類文件。在SUN的JVM中,這些核心類文件存放在JAVA_HOME/jre/lib/rt.jar 。Bootstrap類加載器的獨特之處在于:它是層次結構樹的根節點,因此它沒有父類加載器。
層次結構的下一層是Extension類加載器,它在SUN的JVM中是一個java.net.URLClassLoader,它監控 JAVA_HOME/jre/lib/ext 文件夾擴展JARs 。放在此文件夾下的任何JARs(包括類路徑之外的)都會被自動加載。
層次結構最底層是系統類加載器(應用程序類加載器),它在SUN的JVM中也是一個URLClassLoader 。它監控CLASSPATH里描述的文件夾、JARs 。這個類加載器負責加載應用程序的主類。
如果一個普通的應用程序需要加載一個類(例如java.lang.String),它首先會詢問應用程序類加載器去加載那個類。應用程序類加載器會委托給它的父級Extension類加載器,Extension類加載器委托給它的父級Bootstrap 類加載器,Bootstrap 類加載器然后在rt.jar里加載String.class文件并且使它成為一個可用的java.lang.Class實例。
如果需要加載一個應用程序特定的類文件(例如com.swengsol.UserModel.class),那么委托過程和前面一樣。然而這次,Bootstrap 類加載器在rt.jar里沒能加載到此類文件,現在輪到Extension類加載器同樣沒能加載到此類文件。最后,應用程序類加載器在CLASSPATH里找到了此類文件。然后這個類文件被加載并成為一個JVM可以使用的實例。
每個類加載器里都有緩存,所以每個類加載器首先要檢查自己的緩存看是否已經加載了類文件。如果找到了,則直接返回類文件。
在我們前面的示例中,如果應用程序需要另一個String類,那么Bootstrap 類加載器則直接返回在它緩存里的String類實例。
?
未完待續......
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

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