[ZT]TOMCAT源碼分析
發表于:2007-06-08來源:作者:點擊數:
標簽:
TOMCAT源碼分析(啟動框架) 前言: 本文是我閱讀了TOMCAT源碼后的一些心得。主要是講解TOMCAT的系統框架,以及啟動流程。若有錯漏之處,敬請批評指教! 建議: 畢竟TOMCAT的框架還是比較復雜的,單是從文字上理解,是不那么容易掌握TOMCAT的框架的。所以得實
TOMCAT源碼分析(啟動框架)
前言:
本文是我閱讀了TOMCAT源碼后的一些心得。 主要是講解TOMCAT的系統框架, 以及啟動流程。若有錯漏之處,敬請批評指教!
建議:
畢竟TOMCAT的框架還是比較復雜的, 單是從文字上理解, 是不那么容易掌握TOMCAT的框架的。 所以得實踐、實踐、再實踐。 建議
下載一份TOMCAT的源碼, 調試通過, 然后單步跟蹤其啟動過程。 如果有不明白的地方, 再來查閱本文, 看是否能得到幫助。 我相信這樣效果以及學習速度都會好很多!
1.
Tomcat的整體框架結構
Tomcat的基本框架, 分為4個層次。
Top Level Elements:
Server
Service
Connector
HTTP
AJP
Container
Engine
Host
Context
Component
manager
logger
loader
pipeline
valve
...
站在框架的頂層的是Server和Service
Server: 其實就是BackGroud程序, 在Tomcat里面的Server的用處是啟動和監聽服務端事件(諸如重啟、關閉等命令。 在tomcat的標準配置文件:server.xml里面, 我們可以看到“<Server port="8005" shutdown="SHU
TDOWN" de
bug="0">”這里的"SHUTDOWN"就是server在監聽服務端事件的時候所使用的命令字)
Service: 在tomcat里面, service是指一類問題的
解決方案。 通常我們會默認使用tomcat提供的:Tomcat-Standalone 模式的service。 在這種方式下的service既給我們提供解析jsp和servlet的服務, 同時也提供給我們解析靜態文本的服務。
Connector: Tomcat都是在容器里面處理問題的, 而容器又到哪里去取得輸入信息呢?
Connector就是專干這個的。 他會把從socket傳遞過來的數據, 封裝成Request, 傳遞給容器來處理。
通常我們會用到兩種Connector,一種叫http connectoer, 用來傳遞http
需求的。 另一種叫AJP, 在我們整合apache與tomcat工作的時候, apache與tomcat之間就是通過這個協議來互動的。 (說到apache與tomcat的整合工作, 通常我們的目的是為了讓apache 獲取靜態資源, 而讓tomcat來解析動態的jsp或者servlet。)
Container: 當http connector把需求傳遞給頂級的container: Engin的時候, 我們的視線就應該移動到Container這個層面來了。
在Container這個層, 我們包含了3種容器: Engin, Host, Context.
Engin: 收到service傳遞過來的需求, 處理后, 將結果返回給service( service 是通過 connector 這個媒介來和Engin互動的 ).
Host: Engin收到service傳遞過來的需求后,不會自己處理, 而是交給合適的Host來處理。
Host在這里就是虛擬主機的意思, 通常我們都只會使用一個主機,既“localhost”本地機來處理。
Context: Host接到了從Host傳過來的需求后, 也不會自己處理, 而是交給合適的Context來處理。
比如: <http://127.0.0.1:8080/foo/index.jsp>
<http://127.0.1:8080/bar/index.jsp>
前者交給foo這個Context來處理, 后者交給bar這個Context來處理。
很明顯吧! context的意思其實就是一個web app的意思。
我們通常都會在server.xml里面做這樣的配置
<Context path="/foo" docBase="D:/project/foo/web" />
這個context容器,就是用來干我們該干的事兒的地方的。
Compenent: 接下來, 我們繼續講講component是干什么用的。
我們得先理解一下容器和組件的關系。
需求被傳遞到了容器里面, 在合適的時候, 會傳遞給下一個容器處理。
而容器里面又盛裝著各種各樣的組件, 我們可以理解為提供各種各樣的增值服務。
manager: 當一個容器里面裝了manager組件后,這個容器就支持session管理了, 事實上在tomcat里面的session管理, 就是靠的在context里面裝的manager component.
logger: 當一個容器里面裝了logger組件后, 這個容器里所發生的事情, 就被該組件記錄下來啦! 我們通常會在logs/ 這個目錄下看見 catalina_log.time.txt 以及 localhost.time.txt 和localhost_examples_log.time.txt。 這就是因為我們分別為:engin, host以及context(examples)這三個容器安裝了logger組件, 這也是默認安裝, 又叫做標配 :)
loader: loader這個組件通常只會給我們的context容器使用, loader是用來啟動context以及管理這個context的classloader用的。
pipline: pipeline是這樣一個東西, 當一個容器決定了要把從上級傳遞過來的需求交給子容器的時候, 他就把這個需求放進容器的管道(pipeline)里面去。 而需求傻呼呼得在管道里面流動的時候, 就會被管道里面的各個閥門攔截下來。 比如管道里面放了兩個閥門。 第一個閥門叫做“access_allow_vavle”, 也就是說需求流過來的時候,它會看這個需求是哪個IP過來的, 如果這個IP已經在黑名單里面了, sure, 殺! 第二個閥門叫做“defaul_access_valve”它會做例行的檢查, 如果通過的話,OK, 把需求傳遞給當前容器的子容器。 就是通過這種方式, 需求就在各個容器里面傳遞,流動, 最后抵達目的地的了。
valve: 就是上面所說的閥門啦。
Tomcat里面大概就是這么些東西, 我們可以簡單地這么理解tomcat的框架,它是一種自上而下, 容器里又包含子容器的這樣一種結構。
2. Tomcat的啟動流程
這篇文章是講tomcat怎么啟動的,既然我們大體上了解了TOMCAT的框架結構了, 那么我們可以望文生意地就猜到tomcat的啟動, 會先啟動父容器,然后逐個啟動里面的子容器。 啟動每一個容器的時候, 都會啟動安插在他身上的組件。 當所有的組件啟動完畢, 所有的容器啟動完畢的時候, tomcat本身也就啟動完畢了。
順理成章地, 我們同樣可以猜到, tomcat的啟動會分成兩大部分, 第一步是裝配工作。 第二步是啟動工作。
裝配工作就是為父容器裝上子容器, 為各個容器安插進組件的工作。 這個地方我們會用到digester模式, 至于digester模式什么, 有什么用, 怎么工作的. 請參考 <http://software.ccidnet.com/pub/article/c322_a31671_p2.html>
啟動工作是在裝配工作之后, 一旦裝配成功了, 我們就只需要點燃最上面的一根導線, 整個tomcat就會被激活起來。 這就好比我們要開一輛已經裝配好了的汽車的時候一樣,我們只要把鑰匙插進鑰匙孔,一擰,汽車的引擎就會發動起來,空調就會開起來,
安全裝置就會生效, 如此一來,汽車整個就發動起來了。(這個過程確實和TOMCAT的啟動過程不謀而和, 讓我們不得不懷疑 TOMCAT的設計者是在GE做JAVA
開發的)。
2.1 一些有意思的名稱:
Catalina
Tomcat
Bootstrap
Engin
Host
Context
他們的意思很有意思:
Catalina: 遠程轟炸機
Tomcat: 熊貓轟炸機 -- 轟炸機的一種(這讓我想起了讓國人引以為豪的熊貓手機,是不是英文可以叫做tomcat??? , 又讓我想起了另一則廣告: 波導-手機中的戰斗機、波音-客機中的戰斗機 )
Bootstap: 引導
Engin: 發動機
Host: 主機,領土
Context: 內容, 目標, 上下文
... 在許多許多年后, 現代人類已經滅絕。 后現代生物發現了這些單詞零落零落在一塊。 一個自以為聰明的家伙把這些東西翻譯出來了:
在地勤人員的引導(bootstrap)下, 一架轟炸架(catalina)騰空躍起, 遠看是熊貓轟炸機(tomcat), 近看還是熊貓轟炸機! 憑借著優秀的發動機技術(engin), 這架熊貓轟炸機飛臨了敵國的領土上空(host), 對準目標(context)投下了毀天滅地的核彈頭,波~ 現代生物就這么隔屁了~
綜上所述, 這又不得不讓人聯想到GE是不是也參與了軍事設備的生產呢?
反對美帝國主義! 反對美霸權主義! 和平萬歲! 自由萬歲!
2.2 歷史就是那么驚人的相似! tomcat的啟動就是從org.apache.catalina.startup.Bootstrap這個類悍然啟動的!
在Bootstrap里做了兩件事:
1. 指定了3種類型classloader:
commonLoader: common/classes、common/lib、common/endorsed
catalinaLoader: server/classes、server/lib、commonLoader
sharedLoader: shared/classes、shared/lib、commonLoader
2. 引導Catalina的啟動。
用Reflection技術調用org.apache.catalina.startup.Catalina的process方法, 并傳遞參數過去。
2.3 Catalina.java
Catalina完成了幾個重要的任務:
1. 使用Digester技術裝配tomcat各個容器與組件。
1.1 裝配工作的主要內容是安裝各個大件。 比如server下有什么樣的servcie。 Host會容納多少個context。 Context都會使用到哪些組件等等。
1.2 同時呢, 在裝配工作這一步, 還完成了mbeans的配置工作。 在這里,我簡單地但不十分精確地描述一下mbean是什么,干什么用的。
我們自己生成的對象, 自己管理, 天經地義! 但是如果我們創建了對象了, 想讓別人來管, 怎么辦呢? 我想至少得告訴別人我們都有什么, 以及通過什么方法可以找到 吧! JMX技術給我們提供了一種手段。 JMX里面主要有3種東西。Mbean, agent, connector.
Mbean: 用來映射我們的對象。也許mbean就是我們創建的對象, 也許不是, 但有了它, 就可以引用到我們的對象了。
Agent: 通過它, 就可以找到mbean了。
Connector: 連接Agent的方式。 可以是http的, 也可以是rmi的,還可以直接通過socket。
發生在tomcat 裝配過程中的事情: GlobalResourcesLifecycleListener 類的初始化會被觸發:
protected static Registry registry = MBeanUtils.createRegistry(); 會運行
MBeanUtils.createRegistry() 會依據/org/apache/catalina/mbeans/mbeans-descriptors.xml這個配置文件創建 mbeans. Ok, 外界就有了條途徑訪問tomcat中的各個組件了。(有點像后門兒)
2. 為top level 的server 做初始化工作。 實際上就是做通常會配置給service的兩條connector.(http, ajp)
3. 從server這個容器開始啟動, 點燃整個tomcat.
4. 為server做一個hook程序, 檢測當server shutdown的時候, 關閉tomcat的各個容器用。
5. 監聽8005端口, 如果發送"SHUTDOWN"(默認培植下字符串)過來, 關閉8005serverSocket。
2.4 啟動各個容器
1. Server
觸發Server容器啟動前(before_start), 啟動中(start), 啟動后(after_start)3個事件, 并運行相應的事件處理器。
啟動Server的子容器:Servcie.
2. Service
啟動Service的子容器:Engin
啟動Connector
3. Engin
到了Engin這個層次,以及以下級別的容器, Tomcat就使用了比較一致的啟動方式了。
首先, 運行各個容器自己特有一些任務
隨后, 觸發啟動前事件
立即, 設置標簽,就表示該容器已經啟動
接著, 啟動容器中的各個組件: loader, logger, manager等等
再接著,啟動mapping組件。(注1)
緊跟著,啟動子容器。
接下來,啟動該容器的管道(pipline)
然后, 觸發啟動中事件
最后, 觸發啟動后事件。
Engin大致會這么做, Host大致也會這么做, Context大致還是會這么做。 那么很顯然地, 我們需要在這里使用到代碼復用的技術。 tomcat在處理這個問題的時候, 漂亮地使用了抽象類來處理。 ContainerBase. 最后使得這部分完成復雜功能的代碼顯得干凈利落, 干練爽快, 實在是令人覺得嘆為觀止, 細細品來, 直覺如享佳珍, 另人齒頰留香, 留戀往返??!
Engin的觸發啟動前事件里, 會激活綁定在Engin上的唯一一個Listener:EnginConfig。
這個EnginConfig類基本上沒有做什么事情, 就是把EnginConfig的調試級別設置為和Engin相當。 另外就是輸出幾行文本, 表示Engin已經配置完畢, 并沒有做什么實質性的工作。
注1: mapping組件的用處是, 當一個需求將要從父容器傳遞到子容器的時候, 而父容器又有多個子容器的話, 那么應該選擇哪個子容器來處理需求呢? 這個由mapping 組件來定奪。
4. Host
同Engin一樣, 也是調用ContainerBase里面的start()方法, 不過之前做了些自個兒的任務,就是往Host這個容器的通道(pipline)里面, 安裝了一個叫做
“org.apache.catalina.valves.ErrorReportValve”的閥門。
這個閥門的用處是這樣的: 需求在被Engin傳遞給Host后, 會繼續傳遞給Context做具體的處理。 這里需求其實就是作為參數傳遞的Request, Response。 所以在context把需求處理完后, 通常會改動response。 而這個org.apache.catalina.valves.ErrorReportValve的作用就是檢察response是否包含錯誤, 如果有就做相應的處理。
5. Context
到了這里, 就終于輪到了tomcat啟動中真正的重頭戲,啟動Context了。
StandardContext.start() 這個啟動Context容器的方法被StandardHost調用.
5.1 webappResources 該context所指向的具體目錄
5.2 安裝defaultContex, DefaultContext 就是默認Context。 如果我們在一個Host下面安裝了DefaultContext,而且defaultContext里面又安裝了一個
數據庫連接池資源的話。 那么其他所有的在該Host下的Context, 都可以直接使用這個數據庫連接池, 而不用格外做配置了。
5.3 指定Loader. 通常用默認的org.apache.catalina.loader.WebappLoader這個類。 Loader就是用來指定這個context會用到哪些類啊, 哪些jar包啊這些什么的。
5.4 指定 Manager. 通常使用默認的org.apache.catalina.session. StandardManager 。 Manager是用來管理session的。
其實session的管理也很好實現。 以一種簡單的session管理為例。 當需求傳遞過來的時候, 在Request對象里面有一個sessionId 屬性。 OK, 得到這個sessionId后, 我們就可以把它作為map的key,而value我們可以放置一個HashMap. HashMap里邊兒, 再放我們想放的東西。
5.5 postWorkDirectory (). Tomcat下面有一個work目錄。 我們把臨時文件都扔在那兒去。 這個步驟就是在那里創建一個目錄。 一般說來會在%CATALINA_HOME%/work/Standalone\localhost\ 這個地方生成一個目錄。
5.6 Binding thread。到了這里, 就應該發生 class Loader 互換了。 之前是看得見tomcat下面所有的class和lib. 接下來需要看得見當前context下的class。 所以要設置contextClassLoader, 同時還要把舊的ClassLoader記錄下來,因為以后還要用的。
5.7 啟動 Loader. 指定這個Context具體要使用哪些classes, 用到哪些jar文件。 如果reloadable設置成了true, 就會啟動一個線程來監視classes的變化, 如果有變化就重新啟動Context。
5.8 啟動logger
5.9 觸發安裝在它身上的一個監聽器。
lifecycle.fireLifecycleEvent(START_EVENT, null);
作為監聽器之一,ContextConfig會被啟動. ContextConfig就是用來配置web.xml的。 比如這個Context有多少Servlet, 又有多少Filter, 就是在這里給Context裝上去的。
5.9.1 defaultConfig. 每個context都得配置 tomcat/conf/web.xml 這個文件。
5.9.2 applicationConfig 配置自己的 WEB-INF/web.xml 文件
5.9.3 validateSecurityRoles 權限驗證。 通常我們在訪問/admin 或者/manager的時候,需要用戶要么是admin的要么是manager的, 才能訪問。 而且我們還可以限制那些資源可以訪問, 而哪些不能。 都是在這里實現的。
5.9.4 tldScan: 掃描一下, 需要用到哪些標簽(tag lab)
5.10 啟動 manager
5.11 postWelcomeFiles() 我們通常會用到的3個啟動文件的名稱:
index.html、index.htm、index.jsp 就被默認地綁在了這個context上
5.12 listenerStart 配置listener
5.13 filterStart 配置 filter
5.14 啟動帶有<load-on-startup>1</load-on-startup>的Servlet.
順序是從小到大: 1,2,3… 最后是0
默認情況下, 至少會啟動如下3個的Servlet:
org.apache.catalina.servlets.DefaultServlet
處理靜態資源的Servlet. 什么圖片啊, html啊, css啊, js啊都找他
org.apache.catalina.servlets.InvokerServlet
處理沒有做Servlet Mapping的那些Servlet.
org.apache.jasper.servlet.JspServlet
處理JSP文件的.
5.15 標識context已經啟動完畢。
走了多少個步驟啊, Context總算是啟動完畢嘍。
OK! 走到了這里, 每個容器以及組件都啟動完畢。 Tomcat終于不辭辛勞地為人民服務了!
3. 參考文獻:
<http://jakarta.apache.org/tomcat/>
<http://www.onjava.com/pub/a/onjava/2003/05/14/java_webserver.html>
4. 后記
這篇文章是講解tomcat啟動框架的,還有篇文章是講解TOMCAT里面的消息處理流程的細節的。 文章內容已經寫好了, 現在正在整理階段。 相信很快就可以做出來, 大家共同研究共同進步。
這篇文章是獨自分析TOMCAT源碼所寫的, 所以一定有地方是帶有個人主觀色彩, 難免會有片面之處。若有不當之處敬請批評指教,這樣不僅可以使剛開始研究TOMCAT的兄弟們少走彎路, 我也可以學到東西。
5. tomcat源碼分析(消息處理)
jiupima 回復于:2004-11-19 15:26:56
|
0:前言
我們知道了tomcat的整體框架了, 也明白了里面都有些什么組件, 以及各個組件是干什么用的了。
http://www.csdn.net/Develop/read_article.asp?id=27225
我想,接下來我們應該去了解一下 tomcat 是如何處理jsp和servlet請求的。
1. 我們以一個具體的例子,來跟蹤TOMCAT, 看看它是如何把Request一層一層地遞交給下一個容器, 并最后交給Wrapper來處理的。
以http://localhost:8080/web/login.jsp為例子
(以下例子, 都是以tomcat4 源碼為參考)
這篇心得主要分為3個部分: 前期, 中期, 和末期。
前期:講解了在瀏覽器里面輸入一個URL,是怎么被tomcat抓住的。
中期:講解了被tomcat抓住后,又是怎么在各個容器里面穿梭, 最后到達最后的處理地點。
末期:講解到達最后的處理地點后,又是怎么具體處理的。
2、 前期 Request的born.
在這里我先簡單講一下request這個東西。
我們先看著這個URL:http://localhost:8080/web/login.jsp 它是動用了8080端口來進行socket通訊的。
我們知道, 通過
InputStream in = socket.getInputStream() 和
OutputStream out = socket.getOutputStream()
就可以實現消息的來來往往了。
但是如果把Stream給應用層看,顯然操作起來不方便。
所以,在tomcat 的Connector里面, socket被封裝成了Request和Response這兩個對象。
我們可以簡單地把Request看成管發到服務器來的數據,把Response看成想發出服務器的數據。
但是這樣又有其他問題了??? Request這個對象是把socket封裝起來了, 但是他提供的又東西太多了。
諸如Request.getAuthorization(), Request.getSocket()。 像Authorization這種東西開發人員拿來基本上用不太著,而像socket這種東西,暴露給開發人員又有潛在的危險。 而且啊, 在Servlet Specification里面標準的通信類是ServletRequest和HttpServletRequest,而非這個Request類。 So, So, So. Tomcat必須得搗持搗持Request才行。 最后tomcat選擇了使用搗持模式(應該叫適配器模式)來解決這個問題。它把org.apache.catalina.Request 搗持成了 org.apache.coyote.tomcat4.CoyoteRequest。 而CoyoteRequest又實現了ServletRequest和HttpServletRequest 這兩種接口。 這樣就提供給開發人員需要且剛剛需要的方法了。
ok, 讓我們在 tomcat的頂層容器 - StandardEngin 的invoke()方法這里設置一個斷點, 然后訪問
http://localhost:8080/web/login.jsp , 我們來看看在前期都會路過哪些地方:
1. run(): 536, java.lang.Thread, Thread.java
CurrentThread
2. run():666, org.apache.tomcat.util.threads.ThreadPool$ControlRunnable, ThreadPool.java
ThreadPool
3. runIt():589, org.apache.tomcat.util.net.TcpWorkerThread, PoolTcpEndpoint.java
ThreadWorker
4. processConnection(): 549
org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler, Http11Protocol.java
http protocol parser
5. Process(): 781, org.apache.coyote.http11.Http11Processor, Http11Processor.java
http request processor
6. service(): 193, org.apache.coyote.tomcat4.CoyoteAdapter,CoyoteAdapter.java
adapter
7. invoke(): 995, org.apache.catalina.core.ContainerBase, ContainerBase.java
StandardEngin
1. 主線程
2. 啟動線程池.
3. 調出線程池里面空閑的工作線程。
4. 把8080端口傳過來由httpd協議封裝的數據,解析成Request和Response對象。
5. 使用Http11Processor來處理request
6. 在Http11Processor里面, 又會call CoyoteAdapter來進行適配處理,把Request適配成實現了ServletRequest和HttpServletRequest接口的CoyoteRequest.
7. 到了這里,前期的去毛拔皮工作就基本上搞定,可以交給StandardEngin 做核心的處理工作了。
3. 中期。 在各個容器間的穿梭。
Request在各個容器里面的穿梭大致是這樣一種方式:
每個容器里面都有一個管道(pipline), 專門用來傳送Request用的。
管道里面又有好幾個閥門(valve), 專門用來過濾Request用的。
在管道的低部通常都會放上一個默認的閥們。 這個閥們至少會做一件事情,就是把Request交給子容器。
讓我們來想象一下:
當一個Request進入一個容器后, 它就在管道里面流動,波羅~ 波羅~ 波羅~ 地穿過各個閥門。在流到最后一個閥門的時候,吧唧~ 那個該死的閥門就把它扔給了子容器。 然后又開始 波羅~ 波羅~ 波羅~ ... 吧唧~.... 波羅~ 波羅~ 波羅~ ....吧唧~....
就是通過這種方式, Request 走完了所有的容器。( 感覺有點像消化系統,最后一個地方有點像那里~ )
OK, 讓我們具體看看都有些什么容器, 各個容器里面又都有些什么閥門,這些閥們都對我們的Request做了些什么吧:
3.1 StandardEngin 的pipeline里面放的是:StandardEnginValve
在這里,VALVE做了三件事:
1. 驗證傳遞過來的request是不是httpservletRequest.
2 驗證傳遞過來的 request 是否攜帶了host header信息.
3 選擇相應的host去處理它。(一般我們都只有一個host:localhost,也就是127.0.0.1)。
到了這個地方, 我們的request就已經完成了在Engin這個部分的歷史使命, 通向前途未卜的下一站: host了。
3.2 StandardHost 的pipline里面放的是: StandardHostValve
1. 驗證傳遞過來的request是不是httpservletRequest.
2. 根據Request來確定哪個Context來處理。
Context其實就是webapp, 比如http://localhost:8080/web/login.jsp
這里web就是Context羅!
3. 既然確定了是哪個Context了,那么就應該把那個Context的classloader付給當前線程了。
Thread.currentThread().setContextClassLoader(context.getLoader().getClassLoader());
這樣request就只看得見指定的context下面的classes啊, jar啊這些, 而看不見tomcat本身的類, 什么Engin啊, Valve啊。 不然還得了??!
4. 既然request到了這里了,看來用戶是準備訪問web這個web app了,咋們得更新一下這個用戶的session不是! Ok , 就由manager更新一下用戶的session信息
5. 交給具體的Context 容器去繼續處理Request.
6. Context處理完畢了,把classloader還回來。
3.3 StandardContext 的pipline里面放的是: StandardContextValve
1. 驗證傳遞過來的request是不是httpservletRequest.
2. 如果request意圖不軌,想要訪問/meta-inf, /web-inf這些目錄下的東西,呵呵,沒有用D!
3. 這個時候就會根據Request到底是Servlet,還是jsp,還是靜態資源來決定到底用哪種Wrapper來處理這個Reqeust了。
4. 一旦決定了到底用哪種Wrapper,OK,交給那個Wrapper處理。
4. 末期。 不同的需求是怎么處理的.
StandardWrapper
之前對Wrapper沒有做過講解,其實它是這樣一種東西。
我們在處理Request的時候,可以分成3種。
處理靜態的: org.apache.catalina.servlets.DefaultServlet
處理jsp的: org.apache.jasper.servlet.JspServlet
處理servlet的: org.apache.catalina.servlets.InvokerServlet
不同的request就用這3種不同的servlet去處理。
Wrapper就是對它們的一種簡單的封裝,有了Wrapper后,我們就可以輕松地攔截每次的Request。也可以容易地調用servlet的init()和destroy()方法, 便于管理嘛!
具體情況是這么滴:
如果request是找jsp文件,StandardWrapper里面就會封裝一個org.apache.jasper.servlet.JspServlet去處理它。
如果request是找 靜態資源 ,StandardWrapper里面就會封裝一個org.apache.jasper.servlet.DefaultServlet 去處理它。
如果request是找servlet ,StandardWrapper里面就會封裝一個org.apache.jasper.servlet.InvokerServlet 去處理它。
StandardWrapper同樣也是容器,既然是容器, 那么里面一定留了一個管道給request去穿,管道低部肯定也有一個閥門(注1),用來做最后一道攔截工作.
在這最底部的閥門里,其實就主要做了兩件事:
一是啟動過濾器,讓request在N個過濾器里面篩一通,如果OK! 那就PASS。 否則就跳到其他地方去了。
二是servlet.service((HttpServletRequest) request,(HttpServletResponse) response); 這個方法.
如果是 JspServlet, 那么先把jsp文件編譯成servlet_xxx, 再invoke servlet_xxx的servie()方法。
如果是 DefaultServlet, 就直接找到靜態資源,取出內容, 發送出去。
如果是 InvokerServlet, 就調用那個具體的servlet的service()方法。
ok! 完畢。
注1: StandardWrapper 里面的閥門是最后一道關口了。 如果這個閥門欲意把request交給StandardWrapper 的子容器處理。 對不起, 在設計考慮的時候, Wrapper就被考慮成最末的一個容器, 壓根兒就不會給Wrapper添加子容器的機會! 如果硬是要調用addChild(), 立馬拋出IllegalArgumentException!
參考:
<http://jakarta.apache.org/tomcat/>
<http://www.onjava.com/pub/a/onjava/2003/05/14/java_webserver.html>
|
jiupima 回復于:2004-11-19 15:48:22
|
apache和tomcat的內容先發到著,還有不明白的可以參考本人另外的兩個原創貼子
sco unix 的apache服務器
apache+tomcat+jdk+jk安裝心得
|
jiupima 回復于:2004-11-22 16:28:09
|
[quote:9dc4ec9b1a="jiupima"]apache和tomcat的內容先發到著,還有不明白的可以參考本人另外的兩個原創貼子[/quote:9dc4ec9b1a]
sco unix 的apache服務器
http://bbs.chinaunix.net/forum/viewtopic.php?t=410755&highlight=jiupima
apache+tomcat+jdk+jk安裝心得
http://bbs.chinaunix.net/forum/viewtopic.php?p=2994178#2994178
加入精華,多發原創!
|
納蘭婷 回復于:2004-11-22 22:48:39
|
多謝~~~
|
jiupima 回復于:2004-11-24 09:50:46
|
為什么還不是精華呢,快快加入精華,給我繼續發貼提供動力啊。
|
lc0060305 回復于:2005-02-02 10:45:08
|
寫的不錯,學習
|
alou_pp 回復于:2005-03-24 11:08:53
|
講的真好。不過關于那些轟炸機有點問題。catalina是水上飛機,每天沒事干就在天上轉悠,主要就是巡邏救援之類的事情,應該不算轟炸機;tomcat一直一直都是當戰斗機作航母保護神用的,眼睛明亮,手長劍也長,連F-15都不一定是對手,也就是近年覺得沒有人陪它玩了閑下來沒有事情可作才有時丟丟炸彈炒炒更。
|
原文轉自:http://www.anti-gravitydesign.com