tomcat解析(八)Catalina.createStartDigester

tomcat解析(四)中我們講到了Catalina的load及start方法啓動及準備整個tomcat服務器,而這兩個方法最終又將該任務交由server的initialize及start方法處理,該變更將引用Server類的實例,但初始化時爲空,因此我們需要該對象實例化過程,而該過程盡在Catalina.load方法的第三步驟裏(可看tomcat解析四).首先我們需要了解一下其中的createStartDigester方法,該方法內容如下:

先大概講一下該方法的內容:

1.先實例化一個Digester類的對象,調用其setValidating、setClassLoader等方法設置其某些屬性,這裏不是本文的重點,因此不準備細講。

2.調用了其addObjectCreate、addSetProperties、addSetNext、addRule及addRuleSet等方法

還記得在之前我們講到Digester類的startElement等方法時,有一點講到該類根據標籤路徑名獲取到一年Rule類的List後,分別調用其begin、body及end方法,那個Rule List從何而來呢,答案即將揭曉,我們這裏將通過詳細講解Digester的addObjectCreate等方法來向你揭示這些Ruler的意義。因爲下面這些方法均調用多次,這裏將只舉例說明其作用。

如:
 

  方法內容如下:
 

    在這裏將調用addRule方法,該方法如下:
     

    先看getRules(),該方法如下:

我們可以看到該方法用於實例化一個RuleBase類對象,並且可以瞭解該方法以後每一次調用都只返回第一次生成的對象,因此是一個單例對象,在getRule方法返回後又調用了add方法,此時調用的將是RuleBase.add方法,該方法如下

        

RuleBase類裏掛有一個變量名爲cache的HashMap,該Map將以pattern爲key,各種繼承Rule類對象組成的List爲value.我們再看一下在Digester.startElement裏有如下語句:

List rules = getRules().match(namespaceURI, match);

如上邊的解釋,getRule方法將返回單例的RuleBase對象,然後以標籤路徑名調用其match方法,該方法內容如下:

該方法將主要以調用lookup方法來完成獲取對應Rule List的工作,lookup方法如下:

我們可以看到,該方法將以標籤路徑名pattern爲key值,從cache中取出對應的Rule List,如果我們看一下Catalina.createStartDigester各方法調用時的傳入的pattern值,你會發現是到server.xml一一匹配的,據此我們可大概地理解到這個框架的實現方式:

1.實例化Digester

2.以要解析的xml的結構爲準,調用Digester類各add方法加入對應的Rule.

3.調用Digester.parse方法解析xml文件,則解析每一個標籤時對每一個解析動作將觸發對應Rule的begin、body及end方法。

儘管理解了該框架,但我們仍然需要看一下在Catalina.createStartDigester方法加入了哪些Rule來確定在解析該文件時服務器做了多少事及這些事對整個服務器的啓動有何意義。下面我們先看一下其中幾個比較重要的調用,如

1.addObjectCreate,有如下的調用

 

所加入的Rule實現類爲ObjectCreateRule,該類有begin方法如下

     

    可以看到該方法內容爲實例化一個類,類名可爲實例化該類時初始化的className對象或在調用其begin方法時傳入的Attribute對象(該對象用以表示標籤的屬性)裏className對應的類名,實例化類後又調用digester.push()方法,我們在tomcat解析四中已看到過該方法,該方法會在digester.parse之前調用,參數爲已實例化的Catalina對象。

該類又有end方法如下:

 

可以看到在解析Server的開始標籤時將產生一個org.apache.catalina.core.StandardServer實例,並將之放到棧中,在結束標籤時又將它從棧中取,之所以放於棧中是因爲後續還要對該對象進行很多處理,如下面將講到的

2.addSetProperties

這個方法將加入的Rule實現類爲SetPropertiesRule,這裏先不細講該類啦
3.addSetNext,如
該方法將添加的實現類爲SetNextRule類,該類沒有begin方法,因此在解析開始標籤的時候沒有對應的動作,但該類有end()方法,該方法是在解析結束標籤的事件方法endElement()裏調用的,SetNextRule類的end()方法如下:

    

    該方法內容爲:取出stack頂部的對象,再取出其前一個對象,然後調用前一個對象的方法,方法名爲methodName,比如有如下的調用(事實是有的)

這段代碼將在解析Server標籤的時候觸發,此時在棧中的對象有兩個,一個是最先放入的Catalina對象,而另一個是在addSetNext調用前加入的ObjectCreateRule類所實例化的org.apache.catalina.core.StandardServer實例,因此此時調用Catalina.setServer方法,以StandardServer實例爲參數。這裏是一個非常巧妙的設計,通過相鄰的標籤來生成對應的對象,並且讓上一個對象作爲父對象持有另一對象,因此在加入每一個RULE的時候都必須精妙地設計加入的順序.

4.addRule,比如:
 這個直接對某一個pattern加入對應的Rule,無也講

5.addRuleSet,如
  

 addRuleSet代碼如下:

 

可以看到又調用了RuleSet實現類的addRuleInstances方法,以EngineRuleSet爲例,其addRuleInstances方法如下:

    

可以得知addRuleSet方法主要是用於爲某一想同前輟的標籤加入一批的Rule實現類
我們沒有篇幅來說明tomcat做的每一件事,因此這裏我將影響到後續服務器啓動的一些Rule拿出來講一下。

1.對<Server>標籤

 

實例化了一個org.apache.catalina.core.StandardServer,並以該對象爲參數調用Catalina類的setServer方法,在這裏我們可以回想一下在tomcat解析四裏我們說的server變量所引用的對象是如何得到的呢?該對象有一個設置方法,而該方法即是setServer,因此後續整個服務器的啓動重任將落於剛剛新生的org.apache.catalina.core.StandardServer對象

2.對Service標籤

 

實例化了一個org.apache.catalina.core.StandardService對象,放入棧裏,並以自身爲參數調用棧裏上一個對象的addService方法,通過server.xml我們可以瞭解到<service>標籤是位於<server>標籤之內的,因此此時StandardService的上一個對象爲StandardServer對象(該對象要到結束標籤時纔會被取出來,這又是一個很巧妙的設計,讓xml文件裏有上下級關係的兩個對象實例化後又存在上下級關係,或者是互持有的關係)

3.對Engine標籤有:

 

將會加下以下動作:

 

內容有:實例化org.apache.catalina.core.StandardEngine對象,實例化org.apache.catalina.startup.EngineConfig對象,以該對象爲參數,調用StandardEngine的addLifecycleListener方法,以StandardEngine對象爲參數,調用StandardService.setContainer方法

4.對Host標籤

內容有:內容有:實例化org.apache.catalina.core.StandardHost對象,實例化org.apache.catalina.startup.HostConfig對象,以該對象爲參數,調用StandardHost的addLifecycleListener方法,以StandardHost對象爲參數,調用StandardEngine.addChild方法

5.對Context標籤

內容有:內容有:實例化org.apache.catalina.core.StandardContext對象,實例化org.apache.catalina.startup.ContextConfig對象,以該對象爲參數,調用StandardContext的addLifecycleListener方法,以StandardContext對象爲參數,調用StandardHost.addChild方法

 

方法總結:自上而下地實例了一些tomcat啓動及處理客戶請求的處理類,其中有StandardHost(表示着一個http訪問的主機)、HostConfig、StandardContext(java web中的虛擬目錄)及ContextConfig等,我們後續將會介紹各個主要的啓動類

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章