本文轉自:http://blog.csdn.net/qiqijava/articles/210499.aspx
1.關于Tomcat的基本情況
眾所周知Tomcat是一個免費的開放源碼的Serlvet容器,它是Apache基金會的Jakarta項目中的一個核心項目,也是sun公司官方推薦的servlet和jsp容器,同時它還獲得過多種榮譽。servlet和jsp的最新規范都可以在tomcat的新版本中得到實現。Tomcat具有輕量級和靈活嵌入到應用系統中的優點,所以得到了廣泛的應用。在Tomcat的發展中,Sun在1999年六月宣布參與Jakarta項目的Tomcat servlet容器和Jsp引擎的開發,使得Tomcat在3.x和4.x版之間系統設計上發生了比較大的變化。Tomcat的其他信息我就不多說了。有興趣的朋友可以訪問http://jakarta.apache.org/ 的官方網站得到更多的信息。
因為工作的原因,我改寫了Tomcat的一些代碼,所以我粗略的研究了一下Tomcat3.3和Tomcat4.0的源碼,深深地被這個開放軟件的設計和實現吸引,感覺到這個軟件中有許多值得我們學習和借鑒的地方。我把自己的理解介紹給大家算是拋磚引玉,不足和偏差還望大家批評指正。下面就來讓我們看看從Tomcat那里我們可以得到什么。
2.從Tomcat中學習設計模式
Tomcat的設計和實現處處體現著設計模式的思想,它的基本流程是首先通過解析xml格式的配置文件,獲得系統的配置和應用信息,然后加載定制的組件模塊提供各種系統服務。系統的各部分功能都是通過可以配置的組件模塊來實現的。Tomcat實現中像Observer,Facade,Adapter,Singleton等多種設計模型在Tomcat的源碼中隨處可見,為我們提供了一個很好的學習設計模式的平臺。我主要介紹一下Tomcat中程序流程控制所采用的設計模式,這是一個程序運行的框架。前面提到由于Sun公司的參與,Tomcat雖然基本的流程沒有變化,但是Tomcat3.3和Tomcat4.0版本之間在概念上還是有很大地不同的。Tomcat3.3整體上是模塊化的設計,而Tomcat4.0可以看作是采用面向組件技術進行設計的。組件是比模塊更高級的一個層次。我們可以通過比較它們之間的不同來了解實現一個服務器軟件可以采用的設計模式和實現方式。
2.1Tomcat3.3的基本結構設計
Tomcat3.3采用的是一種模塊化的鏈狀的控制結構,它的主要設計模式有:
Chain of responsibility(責任鏈)
作為一個基于請求響應模式的服務器,在Tomcat3.3中采用一種鏈狀處理的控制模式。請求在鏈上的各個環節上傳遞,在任一環節上可以存在若干個"監聽器"處理它。這樣做的目的是避免請求的發送者和接受者之間的直接耦合,從而可以為其他的對象提供了參與處理請求的機會。采用這個方式不但可以通過"監聽器"實現系統功能,而且可以通過添加新的"監聽器"對象實現系統功能的擴展。
Interceptor(監聽器)
"監聽器"是一個過去使用的名稱,它可以看作 "模塊(module)"的同義詞。它是Tomcat功能模塊構建和擴展的方式。Tomcat3.3的大部分功能都是通過"監聽器"實現的。在Tomcat中提供了一種簡單的鉤子(Hook)機制,監聽器對鉤子中感興趣的事件進行注冊,事件發生后通過鉤子喚醒已注冊的"監聽器"對象,"監聽器"對象對Tomcat內核事件進行處理。這些模塊都是圍繞著"責任鏈"和"策略"的模式進行設計。通過"監聽器"你可以監聽各種特殊事件,進而控制處理請求的各個步驟---解析,認證,授權,會話,響應提交,緩沖區提交等等。
Strategy(策略)
所謂策略是指"定義一組規則,按照規則進行對象封裝,使得他們只在規則內部進行交互"。通過策略模式使得Tomcat作為一個開源項目在開放環境下的開發和演變變得更輕松。通過這種模式把復雜的算法分成模塊然后不同的開發組提供各自的實現。從而實現調用模塊的代碼和模塊的具體實現代碼的分別開發。這樣可以使我們專注于問題的重點,并且減少問題之間的依賴性。在Tomcat中大量采用了策略的設計模式,通過這種方式每一種服務都提供了多種的實現(例如Tomcat中有2-3種認證模塊),在代碼完成后可以從穩定性和性能表現的考慮選擇更好的實現。策略模式對開放式環境下的軟件開發非常有用。
我們通過簡化的類圖(見圖一)和時序圖(見圖二),描述一下Tomcat3.3的程序流程控制如何通過監聽器和責任鏈實現。
圖一 簡化的類圖
關于類圖的簡單說明:
BaseInterceptor:是所有監聽器的基類,描述了基本的模塊功能和對各種事件的缺省處理。
ContextManage:系統的核心控制對象,進行請求處理和系統配置。它維護了全局的屬性、web應用的內容和全局模塊等多種信息,責任鏈的鉤子實現也在其中。
PoolTcpConnector:一個處理TCP連接的連接器對象,從BaseIntercepor派生。它包括一個具體處理socket連接的PoolTcpEndPoint類對象。
PoolTcpEndPoint:處理實際的tcp連接。它有一個連接池對象ThreadPool和運行在獨立線程中的應用邏輯類TcpWorkThread。
TcpWorkThead:處理socket連接事務,調用接口TcpConnectionHandler中的請求處理方法。
Http10Interceptor:從PoolTcpConnector派生,實現了TcpConnectionHandler接口,是一個真正的監聽器對象。它按照Http1.0的協議標準對tcp連接進行處理,調用核心對象ContextManage的服務方法。
圖二 簡化的時序圖
關于時序圖中需要說明的地方:
- 在contextManager初始化后會根據配置信息,加載基本的應用模塊和各種監聽器對象,創建鉤子(Hook)機制,注冊監聽器對象,形成一個責任鏈。然后對各個監聽器對象發出engineInit,engineStart消息。
- 一個請求在經過http10interceptor基本處理后提交到contextManager處理。
- ContextManager的processRequest方法進行請求的處理。按照處理的步驟會順序地發出H_postReadRequest,H_contextMap, H_requestMap等消息。然后從hook中取得對該消息注冊的監聽器對象,調用他們的處理方法,從而實現責任鏈方式。以下的代碼片斷說明了這種方式:
BaseInterceptor ri[];//取得注冊對象ri=defaultContainer.getInterceptors(Container.H_postReadRequest);//執行注冊對象的對消息的處理方法for( int i=0; i< ri.length; i++ ) { status=ri[i].postReadRequest( req ); ......}
- 系統退出時contextManager發出engineStop消息。
Tomcat3.3的基本程序結構就是采用上面介紹的方式設計的。它給我們的設計和開發提供了一個很好的思路,通過這種模式可以輕松的實現一個事件驅動的基于模塊化設計的應用程序。各個功能通過模塊實現,通過對責任鏈上的消息和處理步驟的改動或者添加新的監聽器對象可以非常方便的擴展Tomcat的功能。所以這是一個非常好的設計。
2.2Tomcat4.0的基本結構設計
雖然Tomcat3.x已經實現了一個非常好的設計體系,但是在Sun公司加入后, Tomcat4.0中還是引入了不同的實現方式。主要的區別是Tomcat4.0采用了面向組件的設計方式, Tomcat4.0中的功能是由組件提供的,控制流程通過組件之間的通訊完成。這不同于Tomcat3.3中的基于模塊的鏈式控制結構。
面向組件的技術(CO)是比面向對象的技術(OOP)更高一層的抽象,它融合了面向對象的優點,加入了安全性和可擴展的模塊設計,可以更好的映射問題域空間。采用面向組件的設計會帶來很多好處,可以提高復用性、降低耦合度和通過組裝構成系統等等。面向組件編程中有許多概念與原來面向對象的編程是不同的,例如:
Message(消息):定義抽象操作; Method(方法):定義具體的操作;
Interface(接口):一組消息的集合; Implementation(實現):一組方法的集合;
Module(模塊):靜態的數據結構, Type(類型):動態的數據結構。
軟件組件不同與功能模塊,它具有以下特性:
- 組件是一個自包容的模塊,具有定義清楚的界線,對外提供它的能力、屬性和事件。
- 組件自身不保留狀態。
- 組件可以是一個類,大部分情況下是一組類。
在Java 語言中對面向組件編程的支持是通過JavaBeans模型獲得的。JavaBean組件框架提供了對事件和屬性的支持。Tomcat4.0的組件的就是通過JavaBean技術實現的。這是它和Tomcat3.3中最大的不同。下面我們來看一下Tomcat4.0是如何通過面向組件編程來實現程序流程控制的。
面向組件編程時設計組件是關鍵,從Tomcat4.0中可以看出主要使用了以下的設計模式:
Separation of Concerns(SOC)
設計組件時應該從不同的問題領域,站在不同的觀點上分析,把每一種屬性分別考慮。舉一個例子FileLogger組件,它用于把系統日志信息保存到文件系統中。按照這種模式分析,我們從不同的角度看待它:它如何啟動服務、停止服務和進行通訊?它的具體的功能有哪些?別的組件可以發給它哪些消息?基于這些考慮,FileLogger組件應該實現兩種接口:Lifecycle(生存期接口)和LoggerBase(功能接口)。
Inversion of Control(IOC)這個模式定義的是,組件總是通過外部進行管理的。組件需要的信息總是來源于外部,實際上組件在生存期的各個階段都是被創建它的組件管理的。在Tomcat4.0中就是通過這種組件之間的相互控制和調用實現各個功能的。
按照這些模式分析得到的Tomcat4.0中的組件是既有共性又有特性。共性是Lifecycle接口,特性是不同的功能接口。其中生存期接口處理組件的整個生存期中的各個階段的事件,功能接口提供給其他的組件使用。
具體的功能如何實現我在這里不多介紹了,我主要介紹一下Tomcat4.0中組件的Lifecycle接口的設計。Lifecycle接口實現了組件的生存期管理,控制管理和通訊。創建一個軟件組件和創建一個JavaBean對象一樣,可以參考JavaBean進行理解。我通過一個模擬的Lifecycle接口組件的類圖來描述。(見圖三)
圖三 Lifecycle接口組件類圖
對模擬的Lifecycle接口組件的類圖的說明
- Lifecycle Interface(接口)定義一組組件通訊的Message(消息)。
- 組件實現Lifecycle接口,組件內部定義一個LifecycleSupport對象。需要和該組件通訊的其他組件必須實現LifecycleListener接口,該組件通過add/removeLifecycleListener方法管理需要通訊的其他組件。
- 組件內部狀態改變時如果需要和其他組件通訊時,通過LifecycleSupport對象的fireLifecycleEvent方法通知其他組件。
- 其他組件通過lifecycleEvent方法獲得通知的消息。LifecycleEvent對象是從java.util.EventObject派生的。
- 當然在組件設計和實現中我們也可以直接使用JavaBeans中已經提供的的類如:java.beans.PropertyChangeListener;java.beans.PropertyChangeSupport這樣可以獲得更多的功能特性支持。
通過上面的分析我們可以看到組件成為Tomcat4.0中的核心概念,系統的功能都是通過組件實現的,組件之間的通訊構成了系統的運行控制機制。我們把Tomcat3.3中模塊化的鏈狀控制機制和Tomcat4.0的面向組件的設計進行比較,就會發現Tomcat4.0在設計思想上軟件組件的概念非常明確。Tomcat4.0和Tomcat3.3最主要的區別就在于此。至于面向對象和面向組件的關系和區別,我在這里就不介紹了,有興趣的朋友可以找到很多這方面的資源。
3.從Tomcat源碼中得到高效的軟件組件
Tomcat不但為我們提供了設計和實現系統時的新思路,同時因為它是由組件或者模塊構成的,所以它還為我們提供了大量可用的高效軟件組件。這些組件都可以在我們的程序開發中使用。我簡單列舉一些,需要時可以直接從源碼中取得。
- 一些特殊集合類數據結構如池、隊列、緩存等可用于服務端開發。
\src\share\org\apache\tomcat\util\collections
- 一個簡單的鉤子(Hooks)機制的實現。
src\share\org\apache\tomcat\util\hooks
- 一個簡單線程池(ThreadPool)的實現。
src\share\org\apache\tomcat\util\threads
- 組件Lifecycle接口的設計和實現。
\src\catalina\src\share\org\apache\Catalina
- 常用的日志信息的管理(Logger)的實現。
src\catalina\src\share\org\apache\catalina\logger
- 對xml格式的配置信息進行處理(XmlMapper)的實現。
src\catalina\src\share\org\apache\catalina\util\xml
- 對socket通訊的高級管理和實現(net)。
\src\catalina\src\share\org\apache\catalina\net
通過以上對Tomcat的簡單的介紹,我們可以看出,作為一個開放源碼的項目,Tomcat不但為我們提供了一個應用的平臺,同時它還為我們提供了一個學習和研究設計模式、面向組件技術等理論的實踐平臺。
參考資料
Tomcat3.3源碼和Tomcat4.0源碼http://jakarta.apache.org/tomcat/index.html
《設計模式》