自己最近在學(xué)習(xí)Java Web編程,先是讀了Sun公司的官方文檔Java EE 5的tutorial(http://java.sun.com/javaee/5/docs/tutorial/doc/)中的關(guān)鍵章節(jié),然后學(xué)了一陣Java Passion里的相關(guān)在線課程(見:http://www.javapassion.com/j2ee/),前幾天還看完了一本電子書<<Struts2 in Action>>,但總覺得缺少了什么。這兩天突然想起為什么不把tomcat的源碼下載下來仔細(xì)研究研究呢?記得以前自己一直想學(xué)習(xí)著名的Java Build工具Ant(http://ant.apache.org/)的用法,但怎么看文檔都理解不深,試了幾次效果都不好。最后終于把源碼下載下來讀了其中的主要源碼,頓時(shí)感覺不僅輕松學(xué)會(huì)了Ant的用法,而且知道為什么要那么設(shè)計(jì)。這給我很大的啟發(fā):對(duì)于開源軟件來說,比書籍更好的是在線文檔,比在線文檔更好的源碼本身。其實(shí)tomcat和Ant有很深的內(nèi)在聯(lián)系,tomcat的早期開發(fā)者James Duncan Davidson就是Ant工具的發(fā)明人,為了解決開發(fā)tomcat過程中各種復(fù)雜的build流程他專門創(chuàng)造了Ant。顯然,了解Ant對(duì)讀懂tomcat會(huì)有極大的幫助。tomcat現(xiàn)在的架構(gòu)師Craig McClanahan又是另一個(gè)著名的MVC框架struts的發(fā)明人。
步入正題吧。
首先到tomcat.apache.org里下載最新的源碼包,現(xiàn)在最新的版本是6.0.20,下載后解壓縮,發(fā)現(xiàn)它的根目錄里有一個(gè)build.xml,這是Ant的默認(rèn)輸入文件。tomcat源碼本身是用Eclipse寫的,所以我們要做的第一步是在Eclipse里把tomcat工程部署好,這其實(shí)很容易,在Eclipse里選擇File>New>Project,選擇Java project with an existing Ant buildfile,選擇那個(gè)build.xml就可以了。
然后是下載tomcat的依賴包,這一步也很容易,只要執(zhí)行ant download(可以打開Eclipse的Ant的view以方便操作)就可以了。它會(huì)把下載的依賴包放在一個(gè)名稱為base.path的目錄,最好自己配置一下,它默認(rèn)配置在build.xml.properties.default文件里。下載完依賴包后再ant deploy后就在output/build目錄里得到了可以使用的tomcat。Ant真方便!
Eclipse里要想使得即時(shí)編譯沒有任何錯(cuò)誤提示,需要在build path里配置兩個(gè)變量:一個(gè)是ANT_HOME,另一個(gè)是保存依賴包的TOMCAT_LIBS_BASE,就是保存依賴包的那個(gè)目錄。
看一下tomcat的目錄結(jié)構(gòu),真的很簡(jiǎn)單,啟動(dòng)tomcat的腳本放在bin目錄里,分別有對(duì)應(yīng)windows和unix的兩種腳本。我在Ubuntu環(huán)境下,所以先來看一下它的unix腳本。啟動(dòng)腳本是startup.sh,它實(shí)際上是另一個(gè)腳本catalina.sh的封裝,所以直接跳到catalina.sh,它會(huì)調(diào)用另一個(gè)腳本setclasspath.sh以設(shè)置java,catalina.sh設(shè)置好各種環(huán)境后會(huì)調(diào)用tomcat的啟動(dòng)類:org.apache.catalina.startup.Bootstrap的start方法。
跟蹤一下代碼,Bootstrap類里主要是設(shè)置幾個(gè)不同的ClassLoader和JMX Server,然后通過反射技術(shù)把任務(wù)移交給真正的啟動(dòng)類:org.apache.catalina.startup.Catalina。
怎么樣,這是不是很像啟動(dòng)腳本一樣,先有個(gè)包裝,最后都調(diào)的是catalina,不管是shell還是Java的類。
Catalina里的方法最主要是這個(gè)方法:protected Digester createStartDigester();它是讀取conf/server.xml配置文件進(jìn)行動(dòng)態(tài)加載配置組件的過程,用的是apache的另一個(gè)子項(xiàng)目:Digester,它也是struts讀取配置文件動(dòng)態(tài)加載的機(jī)制,別忘了tomcat的架構(gòu)師可是struts項(xiàng)目的作者啊。
加載完server的層次化組件后,通過調(diào)用 ((Lifecycle) server).start();整個(gè)server就自頂向下啟動(dòng)起來了。另外,代碼中大量運(yùn)用了observer這個(gè)設(shè)計(jì)模式,把各種狀態(tài)的變化通知給相應(yīng)的listener。
在Bootstrap類的源碼中發(fā)現(xiàn)一處小的bug:
if (replace && log.isDebugEnabled())
log.debug("Expanded " + before + " to " + replace);
應(yīng)該是:
if (replace && log.isDebugEnabled())
log.debug("Expanded " + before + " to " + repository);