<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    爪哇東南的自留地

    學(xué)習(xí)探討開源和web開發(fā)

    導(dǎo)航

    <2006年9月>
    272829303112
    3456789
    10111213141516
    17181920212223
    24252627282930
    1234567

    統(tǒng)計

    常用鏈接

    留言簿(1)

    隨筆分類

    隨筆檔案

    相冊

    收藏夾

    life

    technique

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    tomcat 4.1.30啟動過程的源碼分析

    前幾天為了解決sinpool兄的《多線程的問題?!芬惶?,專門看了一下tomcat 4.1.30的源碼,
    其中重點研究了tomcat的啟動這一部分,個人感覺tomcat的源碼還是寫的很清楚易懂,值得一看。
    (以前看過struts的部分代碼,感覺也比較經(jīng)典)????
    然后我看后的代碼整理了一下,附在下面,希望對其他人有用,也希望感興趣的兄弟可以多看看好的代碼,
    肯定對自己的程序設(shè)計和代碼質(zhì)量頗有益處。

    一. 啟動類(包含main()方法的類):
    org.apache.catalina.startup.Bootstrap
    這個類是tomcat的啟動類,主要按照如下步驟,進行主要的啟動工作:
    1. 創(chuàng)建3個ClassLoader:common,catalina和share,它們對應(yīng)tomcat的3個Classloader,我想對tomcat
    的classloader有研究的兄弟對這個肯定不陌生,其中common classloader是緊跟在系統(tǒng)的classloader(也就是
    系統(tǒng)環(huán)境變量中設(shè)置的CLASSPATH所對應(yīng)的classloader),而catalina classloader是common的子classloader,是tomcat
    運行所需要的類的classloader,而shared classloader也是common的子classloader,是和catalina平級的classloader,
    之所以說是shared classloader,是因為它是所有tomcat下面發(fā)布的webapp classloader(每一個web app都有一個自己的classloader)
    的父classloader。它們這3個classloader分別讀取tomcat home下面的common, server和shared三個目錄里面的classes和lib目錄,
    用于初始化自己所控制的類庫和資源。

    2. 創(chuàng)建啟動一個的org.apache.catalina.startup.Catalina類的實例,并調(diào)用它的process方法,這里使用的是java的reflection技術(shù)。
    然后調(diào)用這個實例的process方法,并把Bootstrap接受到的命令行參數(shù)傳遞進去了,這里Bootstrap類并沒有解析傳給它的命令行參數(shù)。
    當(dāng)然在調(diào)用process之前還使用setParentClassLoader方法設(shè)置了一下父classloader。這里簡單介紹一下有關(guān)classloader的一個重要
    特性,就是如果classloader要load一個類時,不是自己先找,而是先把這個任務(wù)委派給自己的父classloader,然后自己的父classloader
    也不找,在把這個任務(wù)委派給自己的父classloader,直到找到最頂層的classloader,然后再自頂向下的找對應(yīng)的這個要load的類的定義,
    如果那個classloader先找到,就返回。所以接合上面第一點介紹的tomcat中3個classloader,大家就可以明白tomca的classloader找類
    的順序了,這個對程序開發(fā)人員來說特別重要。我想使用過tomcat或者其他app server的兄弟肯定碰到過一個類明明存在可就是找不到,
    或者總是找到一個老的版本,我想主要是在多個地方放置的原因,或者哪里有重名的類:-)

    二.org.apache.catalina.startup.Catalina類
    現(xiàn)在程序轉(zhuǎn)到org.apache.catalina.startup.Catalina類里面的process方法。
    這個方法首先設(shè)置一下catalina的home和base目錄,然后通過arguments方法解析命令行參數(shù),
    最后調(diào)用execute()方法啟動server。而execute方法很簡單,就是根據(jù)arguments解析的命令行參數(shù),
    決定是啟動server,還是stop server,如果是start server,就調(diào)用start方法,而下面重點講一下這個start()方法,
    因為才算是一個真正開始的啟動tomcat的地方:-)
    1. start方法首先使用Digester(這個東東是jakarta commons里面的一個用于解析xml文件的工具包,一開始是專門用于解析struts配置文件的,
    后來被抽象成現(xiàn)在的一個通用工具,主要還是用來解析xml配置文件,根據(jù)一些定義的rule自動生成對應(yīng)的類的實例,具體信息可以參考
    apache網(wǎng)站上的文檔)來設(shè)置tomcat配置文件,也就是/conf/server.xml這個文件的解析規(guī)則
    然后通過如下代碼來將配置文件中的數(shù)據(jù)轉(zhuǎn)化成內(nèi)存中的實例:

    代碼:
    ??????? File file = configFile();

    ??????? try {

    ??????????? InputSource is =

    ??????????????? new InputSource("file://" + file.getAbsolutePath());

    ??????????? FileInputStream fis = new FileInputStream(file);

    ??????????? is.setByteStream(fis);

    ??????????? digester.push(this);

    ??????????? digester.parse(is);

    ??????????? fis.close();

    ??????? } catch (Exception e) {

    ??????????? System.out.println("Catalina.start: " + e);

    ??????????? e.printStackTrace(System.out);

    ??????????? System.exit(1);

    ??????? }???
    ????
    ?


    轉(zhuǎn)換的規(guī)則如下(我只作一些簡單的介紹),例如配置文件中的
    a. Server對應(yīng)可以產(chǎn)成一個org.apache.catalina.core.StandardServer類(這個類很重要,是tomcat server的實現(xiàn))
    b. Server/GlobalNamingResources對應(yīng)生成org.apache.catalina.deploy.NamingResources類
    而大家比較熟悉的監(jiān)聽8080端口的類配置如下:
    c. Server/Service/Connector:org.apache.catalina.connector.http.HttpConnector
    d. Server/Service/Engine/Host/Context/:org.apache.catalina.core.StandardContext
    有興趣的兄弟可以參考jakarta commons里面的Digester文檔和org.apache.catalina.startup.Catalina
    這個類里面的createStartDigester方法.
    在這段代碼之后,一個叫server的變量已經(jīng)通過Digester工具生成了,它將會用于啟動tomcat。
    2. 然后程序進行了一些server啟動前的設(shè)置工作,例如重定向log輸出流等等。而server啟動的代碼如下:

    代碼:
    ??????? // Start the new server

    ??????? if (server instanceof Lifecycle) {

    ??????????? try {

    ??????????????? server.initialize();

    ??????????????? ((Lifecycle) server).start();

    ??????????????? try {

    ??????????????????? // Register shutdown hook

    ??????????????????? Runtime.getRuntime().addShutdownHook(shutdownHook);

    ??????????????? } catch (Throwable t) {

    ??????????????????? // This will fail on JDK 1.2. Ignoring, as Tomcat can run

    ??????????????????? // fine without the shutdown hook.

    ??????????????? }

    ??????????????? // Wait for the server to be told to shut down

    ??????????????? server.await();

    ??????????? } catch (LifecycleException e) {

    ??????????????? System.out.println("Catalina.start: " + e);

    ??????????????? e.printStackTrace(System.out);

    ??????????????? if (e.getThrowable() != null) {

    ??????????????????? System.out.println("----- Root Cause -----");

    ??????????????????? e.getThrowable().printStackTrace(System.out);

    ??????????????? }

    ??????????? }

    ??????? }

    ????
    ?


    其中server這個變量就是在剛才Digester解析時創(chuàng)建好的。
    (當(dāng)時這個地方我看了很長時間,后來才發(fā)現(xiàn)是這樣的,因為以前不太了解Digester這個東東)。
    然后大家可以看到server啟動主要是分3步:
    1. initialize方法進行server啟動的初始化操作
    2. start方法啟動server,主要是server中的的service和service中的connector
    3. await方法等待server shutdown
    其中我重點給大家介紹一下initialize方法和start方法
    initialize方法:
    這里面只有一個主要任務(wù),就是逐次調(diào)用server中所有定義的service的initialize方法,
    而每個service的initialize方法中調(diào)用這個service中定義的所有connector的initialize方法,
    而connector的initialize方法則是創(chuàng)建一個serversocket用于接受客戶端的請求就結(jié)束了。
    如果大家看一下tomcat下面conf/server.xml,就可以發(fā)現(xiàn),tomcat默認(rèn)只定義了一個service叫做Tomcat-Standalone,
    而下面只有默認(rèn)定義了3個connector:
    1. 8080端口的http connector
    2. 8443端口的http ssl connector
    3. 8009端口的Coyote/JK2 AJP 1.3 Connector
    我想大家對這3個端口一定不陌生吧。
    start方法:
    這個方法里面有一個tomcat很重要,也是我認(rèn)為tomcat設(shè)計對一個亮點,就是Lifecycle這個東東,它很象一個bus(總線)。
    我想大家進行過程序設(shè)計的一定知道,開始設(shè)計的時候總要根據(jù)一個原則分出幾個模塊來,是為了代碼分塊,或者將
    一部分功能相似的代碼組織成一個模塊,這樣比較清楚,例如一個進銷存系統(tǒng)會有采購,銷售,庫存和財務(wù)等模塊,但是
    我想很多人也碰到過這樣的情況就是雖然分了模塊但是如果在開發(fā)完畢以后,另外一個客戶說只想要其中的銷售模塊,我想
    大部分的開發(fā)人員肯定傻眼,因為雖然當(dāng)時設(shè)計的時候分了模塊,但是這些模塊編寫的時候卻是交織在一起,互相的接口定義
    很模糊,基本上都是直接調(diào)用另一個模塊的方法,這樣肯定分不開。而tomcat的這個Lifecycle的設(shè)計理念就可以解決這個問題的
    一部分,它的原理就象是一個bus(總線),例如一個模塊做完一個動作以后,例如銷售模塊創(chuàng)建好一個訂單后,本來要直接調(diào)用
    庫存模塊的api鎖住一部分庫存(我只是隨便舉個例子,實際業(yè)務(wù)不一定是這樣),這樣銷售模塊就需要依賴庫存模塊了。但是使用了
    bus方式。我們就可以在訂單創(chuàng)建后,向bus上發(fā)送一個訂單創(chuàng)建的消息,而總線有一個事件注冊機制,有點象swing的event,listener,
    例如庫存模塊有一個listener專門用于監(jiān)聽訂單創(chuàng)建的消息,進行處理,這樣2個模塊就互不依賴了。有興趣的兄喜可以看看jcp上面
    的一個叫做infobus的專題。
    當(dāng)然這個方式只是解決有效降低模塊偶合度的一個方面(因為有的時候必須要直接調(diào)用另外一個模塊的接口,
    例如庫存模塊一定要直接缺德一個銷售訂單的信息,那么就需要定義一個接口類來描述訂單的詳細(xì)信息啦,這里就不具體解釋了,
    有空可以專門發(fā)個帖子跟大家探討這個問題:-) ),就是不要顯式觸發(fā)另一個模塊的某個動作,而是通過bus機制來發(fā)送消息,
    而每個模塊都有一個自己的handler,會監(jiān)聽bus,對自感興趣的事件進行處理。tomcat的Lifecycle就是這個東西。
    下面再回到start方法:
    1. 它首先向總線發(fā)送了2個事件:BEFORE_START_EVENT和START_EVENT
    2. 然后調(diào)用每個service的start方法,最后發(fā)送AFTER_START_EVENT消息通知其他程序
    而service的start方法主要進行的動作如下:
    1. 發(fā)送BEFORE_START_EVENT消息
    2. 調(diào)用container的start方法
    3. 然后調(diào)用connector的start方法
    4. 最后發(fā)送AFTER_START_EVENT消息.
    而connector的start方法就是大家最熟悉的socket編程了,大家可以參看org.apache.catalina.connector.http.HttpConnector這個類,
    主要是使用java里面的多線程操作,初始化一個HttpProcessor的線程池,然后通過wait方法阻塞住每個HttpProcessor線程,只有
    當(dāng)接受到一個http請求時,在通過notify方法激活HttpProcessor線程,讓其處理用戶的http請求。

    到此為止主要簡單介紹了一下tomcat 4.1.30的啟動過程,下次有機會的話,可以再看看它的webapp的deploy的管理部分的代碼,然后和大家分享。如果大家對我寫的帖子有什么意見的話,也歡迎批評指正,希望感興趣的兄弟可以一起探討:-) 廢話不說了,很晚了該睡覺了,祝大家周一工作愉快

    posted on 2006-09-13 20:12 ericli 閱讀(243) 評論(0)  編輯  收藏


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 国产亚洲无线码一区二区| 久久久久亚洲AV综合波多野结衣| 久久精品亚洲综合专区| 免费无码又爽又刺激网站直播| 久久久青草青青国产亚洲免观| 一区二区三区免费精品视频| 亚洲一区二区三区在线视频| eeuss影院www天堂免费| 亚洲精品美女久久777777| 国产成人一区二区三区视频免费| 亚洲成色WWW久久网站| 久久国产高潮流白浆免费观看| 亚洲视频中文字幕| 2021免费日韩视频网| 亚洲精品无码久久| 免费国产在线观看老王影院| 一级一级一级毛片免费毛片| 国产AV无码专区亚洲AV毛网站 | 欧洲精品成人免费视频在线观看 | 免费VA在线观看无码| 亚洲国产综合精品一区在线播放| 精品国产呦系列在线观看免费 | 国产亚洲A∨片在线观看| 日韩免费人妻AV无码专区蜜桃| 亚洲日韩乱码中文无码蜜桃| 日韩精品免费电影| 乱人伦中文视频在线观看免费| 国产亚洲一区二区精品| 日本h在线精品免费观看| 亚洲精品人成网线在线播放va | 中国内地毛片免费高清| 亚洲AV无码1区2区久久| 69成人免费视频无码专区| fc2成年免费共享视频网站| 亚洲国色天香视频| 亚洲国产成人a精品不卡在线| 免费精品99久久国产综合精品| 亚洲精品第一综合99久久| 亚洲视频在线精品| 日本一区二区三区免费高清| 精品免费久久久久国产一区|