亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

tomcat源代碼Catalina

系統(tǒng) 1823 0
Catalina的作用是初始化各個(gè)組件,并開始啟動(dòng)各個(gè)組件。
上文中介紹了Bootstrap是怎樣啟動(dòng)Catalina的,如今來看看Catalina的作用:
1,Catalina通過Digester類載入server.xml,實(shí)例化server.xml中各個(gè)組件,并為這些實(shí)例賦值(這個(gè)類是通過擴(kuò)展SAX來完畢的)。
2,調(diào)用server的start方法開啟server組件,server會(huì)一級(jí)一級(jí)的將start傳播下去,這樣各個(gè)組件就從這里開啟了。

3,初始化命名空間(tomcat會(huì)使用JNDI技術(shù),比方在server.xml中配置了數(shù)據(jù)庫連接池的話,就使用了JNDI)。最后還包裝了System.out和System.err。

這里面的重點(diǎn)就是Digester解析server.xml的過程,先來看看start方法:

        public void start() {
    	//這里剔除了一些推斷,日志,server鉤子函數(shù),等代碼
    	......
        if (getServer() == null) {
            load();
        }
   		......
        getServer().start();

        if (await) {
            await();
            stop();
        }
    }
    

依據(jù)第一個(gè)if語句能夠知道server是通過load方法實(shí)例化的。load方法運(yùn)行后,啟動(dòng)服務(wù)器,邏輯非常easy。進(jìn)入load方法:

        public void load() {

    	//這種方法的篇幅過長,我踢掉一些對(duì)流程不重要的代碼
        Digester digester = createStartDigester();

        InputSource inputSource = null;
        InputStream inputStream = null;
        File file = null;
        try {
        	//獲取sever.xml配置文件
            file = configFile();
            inputStream = new FileInputStream(file);
            inputSource = new InputSource(file.toURI().toURL().toString());
        } catch (Exception e) {
            if (log.isDebugEnabled()) {
                log.debug(sm.getString("catalina.configFail", file), e);
            }
        }

        //將sever.xml相應(yīng)的流傳給digester,由digester解析它。
        inputSource.setByteStream(inputStream);
        //這種方法非常重要,它將自己也就是Catalina這個(gè)對(duì)象放到了digester對(duì)象里的一個(gè)棧里面,后面解析xml實(shí)例化server后
        //會(huì)從棧里拿出Catalina對(duì)象調(diào)用它的setServer方法來設(shè)置Catalina.server屬性。server里的service屬性也是通過這樣的形式
        //設(shè)置的。
        digester.push(this);
        digester.parse(inputSource);

        //server實(shí)例化后,將設(shè)置server.catalina屬性,這里Catalina和Server是雙向關(guān)聯(lián)的。
        getServer().setCatalina(this);

        // 包裝了System.out和System.err
        initStreams();

        getServer().init();

    }
    

假設(shè)想搞清楚出digester是怎樣載入server.xml并實(shí)例化各個(gè)組件的,你可能會(huì)進(jìn)入 digester.parse(inputSource)方法,但這種方法
不能告訴你關(guān)鍵的內(nèi)容。來看看digester是個(gè)什么類:
public class Digester extends DefaultHandler2
DefaultHandler2是SAX擴(kuò)展包以下的,不懂SAX的一定要先去了解下SAX,不然看Catalina的源代碼非常費(fèi)勁。回過頭來看看load()方法中的
第一行代碼Digester digester = createStartDigester();進(jìn)入createStartDigester方法:

      
   /**
     * Create and configure the Digester we will be using for startup.
     */
    protected Digester createStartDigester() {
        
        Digester digester = new Digester();

        digester.addObjectCreate("Server",
                                 "org.apache.catalina.core.StandardServer",
                                 "className");
        digester.addSetProperties("Server");
        digester.addSetNext("Server",
                            "setServer",
                            "org.apache.catalina.Server");

        digester.addObjectCreate("Server/GlobalNamingResources",
                                 "org.apache.catalina.deploy.NamingResources");
        digester.addSetProperties("Server/GlobalNamingResources");
        digester.addSetNext("Server/GlobalNamingResources",
                            "setGlobalNamingResources",
                            "org.apache.catalina.deploy.NamingResources");

        digester.addObjectCreate("Server/Listener",
                                 null, // MUST be specified in the element
                                 "className");
        digester.addSetProperties("Server/Listener");
        digester.addSetNext("Server/Listener",
                            "addLifecycleListener",
                            "org.apache.catalina.LifecycleListener");

        digester.addObjectCreate("Server/Service",
                                 "org.apache.catalina.core.StandardService",
                                 "className");
        digester.addSetProperties("Server/Service");
        digester.addSetNext("Server/Service",
                            "addService",
                            "org.apache.catalina.Service");

        digester.addObjectCreate("Server/Service/Listener",
                                 null, // MUST be specified in the element
                                 "className");
        digester.addSetProperties("Server/Service/Listener");
        digester.addSetNext("Server/Service/Listener",
                            "addLifecycleListener",
                            "org.apache.catalina.LifecycleListener");

        //Executor
        digester.addObjectCreate("Server/Service/Executor",
                         "org.apache.catalina.core.StandardThreadExecutor",
                         "className");
        digester.addSetProperties("Server/Service/Executor");

        digester.addSetNext("Server/Service/Executor",
                            "addExecutor",
                            "org.apache.catalina.Executor");

        digester.addRule("Server/Service/Connector",
                         new ConnectorCreateRule());
        digester.addRule("Server/Service/Connector",
                         new SetAllPropertiesRule(new String[]{"executor"}));
        digester.addSetNext("Server/Service/Connector",
                            "addConnector",
                            "org.apache.catalina.connector.Connector");

        digester.addObjectCreate("Server/Service/Connector/Listener",
                                 null, // MUST be specified in the element
                                 "className");
        digester.addSetProperties("Server/Service/Connector/Listener");
        digester.addSetNext("Server/Service/Connector/Listener",
                            "addLifecycleListener",
                            "org.apache.catalina.LifecycleListener");

        // Add RuleSets for nested elements
        digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));
        digester.addRuleSet(new EngineRuleSet("Server/Service/"));
        digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
        digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
        addClusterRuleSet(digester, "Server/Service/Engine/Host/Cluster/");
        digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));

        // When the 'engine' is found, set the parentClassLoader.
        digester.addRule("Server/Service/Engine",
                         new SetParentClassLoaderRule(parentClassLoader));
        addClusterRuleSet(digester, "Server/Service/Engine/Cluster/");

        return (digester);

    }
    

細(xì)致看著這些參數(shù),xml文檔的節(jié)點(diǎn)名稱都有與之相應(yīng)的類比方Server節(jié)點(diǎn)對(duì)象org.apache.catalina.core.StandardServer

digester實(shí)例化Server時(shí)是實(shí)例化了它的子類StanderServer。

進(jìn)入addObjectCreate方法:

      public void addObjectCreate(String pattern, String className,
                                String attributeName) {

        addRule(pattern,
                new ObjectCreateRule(className, attributeName));

    }
    

每調(diào)用一個(gè)add*方法都為pattern映射了一個(gè)Rule的子類,addSetProperties,addSetNext都為pattern映射了一個(gè)Rule的子類。
這個(gè)映射關(guān)系被存放在RulesBase.cache中:

      public class RulesBase implements Rules {

    protected HashMap<String,List<Rule>> cache =
        new HashMap<String,List<Rule>>();
}
    

從這個(gè)數(shù)據(jù)結(jié)構(gòu)能夠知道每一個(gè)節(jié)點(diǎn)的完整名稱相應(yīng)一個(gè)Rule的list集合。來看看Rule是怎樣定義的:
      public abstract class Rule {
    public Digester getDigester() {
        return (this.digester);
    }
    public void begin(String namespace, String name, Attributes attributes)
        throws Exception {
        begin(attributes);
    }
    public void end(String namespace, String name)
        throws Exception {
        end();
    }
}
    

begin和end是它的核心方法(有的子類可能沒有當(dāng)中的某個(gè)方法,這里為了說明xml的解析流程所以說它們重要)。講到這里是想說明:digster事先為xml中的每一個(gè)節(jié)點(diǎn)定義了多個(gè)規(guī)則。上面提到Degister繼承自DefaultHandler2,并重寫了它的startDocument(),startElement(),endDocument()endElement()等方法。Degister內(nèi)部定義了一個(gè)XMLReader類型的成員變量reader,并將自己作為ContentHandler和DTDHandler 傳給自己的成員變量reader。那么reader在解析xml的時(shí)候就會(huì)回調(diào)Digster繼承自DefaultHandler2的startDocument(),startElement(),endDocument(),endElement()等回調(diào)方法。在回調(diào)方法中就會(huì)調(diào)用與當(dāng)前節(jié)點(diǎn)相應(yīng)的Rule類的回調(diào)方法。如今拿Server的初始化來舉例:在上面提到的createStartDigester()方法中為Server加入了三個(gè)規(guī)則:
         digester.addObjectCreate("Server",
                                 "org.apache.catalina.core.StandardServer",
                                 "className");
        digester.addSetProperties("Server");
        digester.addSetNext("Server",
                            "setServer",
                            "org.apache.catalina.Server");
    

這三個(gè)方法內(nèi)部會(huì)分別創(chuàng)建三個(gè)規(guī)則類,ObjectCreateRule,SetPropertiesRule,SetNextRule。這三個(gè)類的作用各自是創(chuàng)建指定類,將xml標(biāo)簽上的屬性賦值給改類,將該類賦值給它的上級(jí)類。這三個(gè)類被創(chuàng)建后加入到了一個(gè)以“Server”為鍵的map中前面提到的RulesBase.cache。在reader類解析xml到<Server>標(biāo)簽的開始節(jié)點(diǎn)時(shí)會(huì)調(diào)用startElement()方法,并將當(dāng)前節(jié)點(diǎn)的節(jié)點(diǎn)名和屬性值等一系列值傳給改方法。方法內(nèi)部則通過節(jié)點(diǎn)全名稱獲取相應(yīng)的規(guī)則類Rule對(duì)象的list結(jié)合,并挨個(gè)調(diào)用rule對(duì)象的begin方法。以server相應(yīng)的ObjectCreateRule規(guī)則為例:
          public void begin(String namespace, String name, Attributes attributes)
            throws Exception {
        Class<?> clazz = digester.getClassLoader().loadClass(realClassName);
        Object instance = clazz.newInstance();
        digester.push(instance);
    }
    

創(chuàng)建了與server相應(yīng)的實(shí)例(實(shí)例名是org.apache.catalina.core.StandardServer或是屬性classname對(duì)象的值)并放在了digest的一個(gè)名為stack屬性的棧頂。前面的load方法中digester將當(dāng)前類對(duì)象也就是Catalina對(duì)象push到了stack里面,這時(shí)候Catalina應(yīng)該在stack的底端,由于之前stack里沒有數(shù)據(jù)。server標(biāo)簽是server.xml的第一個(gè)標(biāo)簽,這時(shí)候解析到它的開始標(biāo)簽并調(diào)用了與它對(duì)象的ObjectCreateRule規(guī)則的begin方法初始化了server對(duì)象并后push到了stack里面,那么此時(shí)stack有兩個(gè)元素,Catalina在棧底,server在棧頂。ObjectCreateRule的start方法結(jié)束后會(huì)繼續(xù)調(diào)用SetPropertiesRule的start方法,這個(gè)類是將標(biāo)簽的屬性值賦值給上面創(chuàng)建的對(duì)象,它的begin方法的第一步就是從stack獲取對(duì)象,然后將標(biāo)簽上的屬性值賦值給該對(duì)象比方<Server port="8005" shutdown="SHUTDOWN">中的port和shutdown屬性。最后是SetNextRule類,這個(gè)類僅僅有一個(gè)end方法是在遇到</Server>的結(jié)束標(biāo)簽時(shí)調(diào)用的。以下是該方法的源代碼:
          @Override
    public void end(String namespace, String name) throws Exception {

        Object child = digester.peek(0);
        Object parent = digester.peek(1);
        if (digester.log.isDebugEnabled()) {
            if (parent == null) {
                digester.log.debug("[SetNextRule]{" + digester.match +
                        "} Call [NULL PARENT]." +
                        methodName + "(" + child + ")");
            } else {
                digester.log.debug("[SetNextRule]{" + digester.match +
                        "} Call " + parent.getClass().getName() + "." +
                        methodName + "(" + child + ")");
            }
        }

        IntrospectionUtils.callMethod1(parent, methodName,
                child, paramType, digester.getClassLoader());
                
    }
    
在調(diào)用這種方法前,degister的成員變量stack已經(jīng)push和pop好幾個(gè)對(duì)象了,每次標(biāo)簽開始解析時(shí)創(chuàng)建對(duì)象push到stack里面,標(biāo)簽結(jié)束后從stack里pop出來。由于<Server>標(biāo)簽是頂層標(biāo)簽,所以server對(duì)象最先被創(chuàng)建并push到stack里面(Catalina一直在棧底),最后被pop出來,所以結(jié)束標(biāo)簽</server>解析時(shí)和開始一樣,stack依舊還是兩個(gè)元素,server在棧頂,Catalina在棧底。 Object child = digester.peek(0);Object parent = digester.peek(1);分別取出了棧頂和棧底的元素。server.xml的解析不是非常好敘述,它的關(guān)系有點(diǎn)復(fù)雜。要記住一點(diǎn)server.xml的每一級(jí)標(biāo)簽相應(yīng)一個(gè)tomcat組件,被外層標(biāo)簽包裹的標(biāo)簽是外層標(biāo)簽的一個(gè)屬性比方serveice是server的一個(gè)屬性。xml在被解析時(shí)會(huì)依據(jù)當(dāng)前的事件(開始,或結(jié)束)來調(diào)用相應(yīng)節(jié)點(diǎn)的解析規(guī)則,創(chuàng)建對(duì)象,并通過棧來完畢對(duì)象之間的關(guān)聯(lián)關(guān)系。


tomcat源代碼Catalina


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 国产综合久久久久 | 欧美一级性视频 | 亚洲麻豆国产精品 | 人人干夜夜操 | 伊人网综合在线观看 | 亚洲一级毛片免费在线观看 | 国内精品久久久久久久999下 | 免费观看呢日本天堂视频 | 久久成人免费观看草草影院 | 日本一区二区三区免费高清在线 | 亚洲成人观看 | 大色综合色综合资源站 | 日本aa在线 | 亚洲成av人片天堂网 | 国产亚洲精品第一区在线观看 | 奇米影视777在线观看 | 日韩毛片最新看 | 日本一级毛片视频无遮挡免费 | 免费看色 | 色偷偷资源网 | 在线观看欧美精品 | 亚洲欧美日韩综合 | 精品特级一级毛片免费观看 | 国产精品视频福利视频网 | 国产精品福利午夜h视频 | 久久高清影院 | 欧美香蕉在线 | 精品国产福利久久久 | 欧美综合天天夜夜久久 | 99久久免费国产精品 | 欧美v亚洲v国产v | 美国免费三片在线观看 | 老司机午夜永久在线观看 | 午夜私人影院在线观看 | 日韩黄网 | 国产区精品一区二区不卡中文 | 久久爱www.| 四虎影院在线视频 | 欧美国产精品久久 | 一级特黄国产高清毛片97看片 | 久久久综合九色合综 |