日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

How Tomcat Works(十八)

系統(tǒng) 2147 0

在前面的文章中,如果我們要啟動(dòng)tomcat容器,我們需要使用Bootstrap類來實(shí)例化連接器、servlet容器、Wrapper實(shí)例和其他組件,然后調(diào)用各個(gè)對(duì)象的set方法將它們關(guān)聯(lián)起來;這種配置應(yīng)用程序的方法有一個(gè)明顯的缺陷,即所有的配置都必須硬編碼。調(diào)整組件配置和屬性值都必須要重新編譯Bootstrap類。幸運(yùn)的是,Tomcat的設(shè)計(jì)者使用了一種更加優(yōu)雅的配置方式,即使用一個(gè)名為server.xml的XML文件來對(duì)應(yīng)用程序進(jìn)行配置。server.xml文件中的每個(gè)元素都會(huì)轉(zhuǎn)換為一個(gè)java對(duì)象,元素的屬性會(huì)用于設(shè)置java對(duì)象的屬性,這樣,就可以通過簡(jiǎn)單的編輯server.xml文件來修改tomcat的配置。

Tomcat使用了開源庫Digester來將xml文件中的元素轉(zhuǎn)換成java對(duì)象。

由于一個(gè)Context實(shí)例表示一個(gè)Web應(yīng)用程序,因此配置Web應(yīng)用程序是通過對(duì)已經(jīng)實(shí)例化的Context實(shí)例進(jìn)行配置完成的。用來配置Web應(yīng)用程序的XML文件的名稱是web.xml,該文件位于Web應(yīng)用程序的WEB-INF目錄下。

下面來介紹Digester庫,Digester庫是Apache軟件基金會(huì)的Jatarta項(xiàng)目下的子Commons項(xiàng)目下的一個(gè)開源項(xiàng)目,它的主頁地址是http://commons.apache.org/proper/commons-digester/

org.apache.commons.digester3.Digester類是Digester庫中的主類,該類可用于解析XML文件,對(duì)于XML文件中的每個(gè)元素,Digester對(duì)象都會(huì)檢查它是否要做事先預(yù)定義的事件,在調(diào)用Digester對(duì)象的parse()方法之前,程序員要先定義好Digester對(duì)象執(zhí)行哪些動(dòng)作。

因此,程序員要先定義好模式,然后將每個(gè)模式與一條或多條規(guī)則相關(guān)聯(lián)。

模式通常是xml文件里面元素的路徑,類似于xpath的語法路徑

規(guī)則指明了當(dāng)Digester對(duì)象遇到了某個(gè)特殊的模式時(shí)要執(zhí)行的一個(gè)或多個(gè)動(dòng)作,規(guī)則是org.apache.commons.digester3.Rule類的實(shí)例,Digester類開源包含0個(gè)或多個(gè)Rule對(duì)象,在Digester實(shí)例中,這些規(guī)則和其相關(guān)聯(lián)的模式都存儲(chǔ)在由org.apache.commons.digester3.Rules接口表示的一類存儲(chǔ)器中,每當(dāng)把一條規(guī)則添加到Digester實(shí)例中時(shí),Rule對(duì)象都會(huì)被添加到Rules對(duì)象中。

另外,Rule類有begin()方法和end()方法,在解析xml文件時(shí),當(dāng)Digester實(shí)例遇到匹配某個(gè)模式的元素的開始標(biāo)簽時(shí),它會(huì)調(diào)用相應(yīng)的Rule對(duì)象的begin()方法,而當(dāng)Digester實(shí)例遇到相應(yīng)元素的結(jié)束標(biāo)簽時(shí),它會(huì)調(diào)用Rule對(duì)象的end()方法。

在使用Digester庫時(shí),我們需要先導(dǎo)入相關(guān)依賴jar

      
        <
      
      
        dependency
      
      
        >
      
      
        <
      
      
        groupId
      
      
        >
      
      org.apache.commons
      
        </
      
      
        groupId
      
      
        >
      
      
        <
      
      
        artifactId
      
      
        >
      
      commons-digester3
      
        </
      
      
        artifactId
      
      
        >
      
      
        <
      
      
        version
      
      
        >
      
      3.2
      
        </
      
      
        version
      
      
        >
      
      
        <
      
      
        classifier
      
      
        >
      
      with-deps
      
        </
      
      
        classifier
      
      
        >
      
      
        </
      
      
        dependency
      
      
        >
      
    

第一個(gè)示例應(yīng)用程序演示如何使用Digester庫動(dòng)態(tài)的創(chuàng)建對(duì)象,并設(shè)置相應(yīng)的屬性值。

employee1.xml文件內(nèi)容如下

      
        <?
      
      
        xml version="1.0" encoding="ISO-8859-1"
      
      
        ?>
      
      
        <
      
      
        employee 
      
      
        firstName
      
      
        ="Brian"
      
      
         lastName
      
      
        ="May"
      
      
        >
      
      
        </
      
      
        employee
      
      
        >
      
    

我們需要根據(jù)上面的xml文件創(chuàng)建Employee對(duì)象,并設(shè)置相應(yīng)屬性,Employee類代碼如下:

      
        public
      
      
        class
      
      
         Employee {
  
      
      
        private
      
      
         String firstName;
  
      
      
        private
      
      
         String lastName;
  
      
      
        private
      
       ArrayList offices = 
      
        new
      
      
         ArrayList();
    
  
      
      
        public
      
      
         Employee() {
    System.out.println(
      
      "Creating Employee"
      
        );
  }
  
      
      
        public
      
      
         String getFirstName() {
    
      
      
        return
      
      
         firstName;
  }
  
      
      
        public
      
      
        void
      
      
         setFirstName(String firstName) {
    System.out.println(
      
      "Setting firstName : " +
      
         firstName);
    
      
      
        this
      
      .firstName =
      
         firstName;
  }
  
      
      
        public
      
      
         String getLastName() {
    
      
      
        return
      
      
         lastName;
  }
  
      
      
        public
      
      
        void
      
      
         setLastName(String lastName) {
    System.out.println(
      
      "Setting lastName : " +
      
         lastName);
    
      
      
        this
      
      .lastName =
      
         lastName;
  }
  
      
      
        public
      
      
        void
      
      
         addOffice(Office office) {
    System.out.println(
      
      "Adding Office to this employee"
      
        );
    offices.add(office);
  }
  
      
      
        public
      
      
         ArrayList getOffices() {
    
      
      
        return
      
      
         offices;
  }
  
      
      
        public
      
      
        void
      
      
         printName() {
    System.out.println(
      
      "My name is " + firstName + " " +
      
         lastName);
  }
}
      
    

現(xiàn)在寫一個(gè)測(cè)試類Test01,它使用Digester類,并為其添加創(chuàng)建Employee對(duì)象和設(shè)置其屬性的規(guī)則。

      
        public
      
      
        class
      
      
         Test01 {

    
      
      
        public
      
      
        static
      
      
        void
      
      
         main(String[] args) {
       
      
      
        
        InputStream inputStream 
      
      = 
      
        null
      
      
        ;
        Digester digester 
      
      = 
      
        new
      
      
         Digester();
        
      
      
        //
      
      
         add rules
      
      
        digester.addObjectCreate("employee","ex15.pyrmont.digestertest.Employee"
      
        );
        digester.addSetProperties(
      
      "employee"
      
        );
        digester.addCallMethod(
      
      "employee", "printName"
      
        );

        
      
      
        try
      
      
         {
            inputStream 
      
      = Thread.currentThread().getContextClassLoader().getResourceAsStream("employee1.xml");
            Employee employee =
      
         (Employee) digester.parse(inputStream);
            System.out.println(
      
      "First name : " +
      
         employee.getFirstName());
            System.out.println(
      
      "Last name : " +
      
         employee.getLastName());
        } 
      
      
        catch
      
      
         (Exception e) {
            e.printStackTrace();
        } 
      
      
        finally
      
      
         {
            
      
      
        if
      
       (inputStream != 
      
        null
      
      
        ) {
                
      
      
        try
      
      
         {
                    inputStream.close();
                } 
      
      
        catch
      
      
         (IOException e) {
                    
      
      
        //
      
      
         TODO Auto-generated catch block
      
      
                            e.printStackTrace();
                }
            }
        }
    }

}
      
    

第二個(gè)示例演示如何利用Digester庫創(chuàng)建兩個(gè)對(duì)象,并建立他們之間的關(guān)系

employee2.xml 文件內(nèi)容如下

      
        <?
      
      
        xml version="1.0" encoding="ISO-8859-1"
      
      
        ?>
      
      
        <
      
      
        employee 
      
      
        firstName
      
      
        ="Freddie"
      
      
         lastName
      
      
        ="Mercury"
      
      
        >
      
      
        <
      
      
        office 
      
      
        description
      
      
        ="Headquarters"
      
      
        >
      
      
        <
      
      
        address 
      
      
        streetName
      
      
        ="Wellington Avenue"
      
      
         streetNumber
      
      
        ="223"
      
      
        />
      
      
        </
      
      
        office
      
      
        >
      
      
        <
      
      
        office 
      
      
        description
      
      
        ="Client site"
      
      
        >
      
      
        <
      
      
        address 
      
      
        streetName
      
      
        ="Downing Street"
      
      
         streetNumber
      
      
        ="10"
      
      
        />
      
      
        </
      
      
        office
      
      
        >
      
      
        </
      
      
        employee
      
      
        >
      
    

然后我們還需要?jiǎng)?chuàng)建Office類和Address類

Office類代碼如下:

      
        public
      
      
        class
      
      
         Office {
  
      
      
        private
      
      
         Address address;
  
      
      
        private
      
      
         String description;
  
      
      
        public
      
      
         Office() {
    System.out.println(
      
      "..Creating Office"
      
        );
  }
  
      
      
        public
      
      
         String getDescription() {
    
      
      
        return
      
      
         description;
  }
  
      
      
        public
      
      
        void
      
      
         setDescription(String description) {
    System.out.println(
      
      "..Setting office description : " +
      
         description);
    
      
      
        this
      
      .description =
      
         description;
  }
  
      
      
        public
      
      
         Address getAddress() {
    
      
      
        return
      
      
         address;
  }
  
      
      
        public
      
      
        void
      
      
         setAddress(Address address) {
    System.out.println(
      
      "..Setting office address : " +
      
         address);
    
      
      
        this
      
      .address =
      
         address;
  }
}
      
    

Address類代碼如下:

      
        public
      
      
        class
      
      
         Address {
  
      
      
        private
      
      
         String streetName;
  
      
      
        private
      
      
         String streetNumber;
  
      
      
        public
      
      
         Address() {
    System.out.println(
      
      "....Creating Address"
      
        );
  }
  
      
      
        public
      
      
         String getStreetName() {
    
      
      
        return
      
      
         streetName;
  }
  
      
      
        public
      
      
        void
      
      
         setStreetName(String streetName) {
    System.out.println(
      
      "....Setting streetName : " +
      
         streetName);
    
      
      
        this
      
      .streetName =
      
         streetName;
  }
  
      
      
        public
      
      
         String getStreetNumber() {
    
      
      
        return
      
      
         streetNumber;
  }
  
      
      
        public
      
      
        void
      
      
         setStreetNumber(String streetNumber) {
    System.out.println(
      
      "....Setting streetNumber : " +
      
         streetNumber);
    
      
      
        this
      
      .streetNumber =
      
         streetNumber;
  }
  
      
      
        public
      
      
         String toString() {
    
      
      
        return
      
       "...." + streetNumber + " " +
      
         streetName; 
  }
}
      
    

下面是Test02類的定義,該類使用一個(gè)Digester對(duì)象,并為其添加規(guī)則

      
        public
      
      
        class
      
      
         Test02 {

    
      
      
        public
      
      
        static
      
      
        void
      
      
         main(String[] args) {
        
      
      
        InputStream inputStream = 
      
        null
      
      
        ;
        Digester digester 
      
      = 
      
        new
      
      
         Digester();
        
      
      
        //
      
      
         add rules
      
      
        digester.addObjectCreate("employee"
      
        ,
                
      
      "ex15.pyrmont.digestertest.Employee"
      
        );
        digester.addSetProperties(
      
      "employee"
      
        );
        digester.addObjectCreate(
      
      "employee/office"
      
        ,
                
      
      "ex15.pyrmont.digestertest.Office"
      
        );
        digester.addSetProperties(
      
      "employee/office"
      
        );
        digester.addSetNext(
      
      "employee/office", "addOffice"
      
        );
        digester.addObjectCreate(
      
      "employee/office/address"
      
        ,
                
      
      "ex15.pyrmont.digestertest.Address"
      
        );
        digester.addSetProperties(
      
      "employee/office/address"
      
        );
        digester.addSetNext(
      
      "employee/office/address", "setAddress"
      
        );
        
      
      
        try
      
      
         {
            inputStream 
      
      =
      
         Thread.currentThread().getContextClassLoader()
                    .getResourceAsStream(
      
      "employee2.xml");
            Employee employee =
      
         (Employee) digester.parse(inputStream);
            ArrayList offices 
      
      =
      
         employee.getOffices();
            Iterator iterator 
      
      =
      
         offices.iterator();
            System.out
                    .println(
      
      "-------------------------------------------------"
      
        );
            
      
      
        while
      
      
         (iterator.hasNext()) {
                Office office 
      
      =
      
         (Office) iterator.next();
                Address address 
      
      =
      
         office.getAddress();
                System.out.println(office.getDescription());
                System.out.println(
      
      "Address : " +
      
         address.getStreetNumber()
                        
      
      + " " +
      
         address.getStreetName());
                System.out.println(
      
      "--------------------------------"
      
        );
            }

        } 
      
      
        catch
      
      
         (Exception e) {
            e.printStackTrace();
        } 
      
      
        finally
      
      
         {
            
      
      
        if
      
       (inputStream != 
      
        null
      
      
        ) {
                
      
      
        try
      
      
         {
                    inputStream.close();
                } 
      
      
        catch
      
      
         (IOException e) {
                    
      
      
        //
      
      
         TODO Auto-generated catch block
      
      
                            e.printStackTrace();
                }
            }
        }

    }
}
      
    

Rule類包含了一些方法,其中最重要的兩個(gè)方法是begin()方法和end()方法,當(dāng)Digester實(shí)例遇到某個(gè)XML元素的開始標(biāo)簽時(shí),它會(huì)調(diào)用它所包含的匹配Rule對(duì)象的begin()方法,方法簽名如下:

public void begin( String namespace, String name, Attributes attributes ) throws Exception

當(dāng)Digester實(shí)例遇到某個(gè)XML元素的結(jié)束標(biāo)簽時(shí),它會(huì)調(diào)用它所包含的匹配Rule對(duì)象的end()方法,方法簽名如下:

public void end( String namespace, String name ) throws Exception

Digester對(duì)象是如何完成這些工作的呢?當(dāng)調(diào)用Digester對(duì)象的addObjectCreate()方法、addCallMethod()方法、addSetNext()方法或其他方法時(shí),都會(huì)間接地調(diào)用Digester類的addRule()方法;該方法將一個(gè)Rule對(duì)象和它所匹配的模式添加到Digester對(duì)象的Rules集合中。

addRule()方法實(shí)現(xiàn)如下:

      
        public
      
      
        void
      
      
         addRule( String pattern, Rule rule )
    {
        rule.setDigester( 
      
      
        this
      
      
         );
        getRules().add( pattern, rule );
    }
      
    

查看Digester類的addObjectCreate()方法的重載實(shí)現(xiàn)如下:

      
        public
      
      
        void
      
      
         addObjectCreate( String pattern, String className )
    {
        addRule( pattern, 
      
      
        new
      
      
         ObjectCreateRule( className ) );
    }
   
      
      
        public
      
      
        void
      
       addObjectCreate( String pattern, Class<?>
      
         clazz )
    {
        addRule( pattern, 
      
      
        new
      
      
         ObjectCreateRule( clazz ) );
    }
   
      
      
        public
      
      
        void
      
      
         addObjectCreate( String pattern, String className, String attributeName )
    {
        addRule( pattern, 
      
      
        new
      
      
         ObjectCreateRule( className, attributeName ) );
    }
   
      
      
        public
      
      
        void
      
       addObjectCreate( String pattern, String attributeName, Class<?>
      
         clazz )
    {
        addRule( pattern, 
      
      
        new
      
      
         ObjectCreateRule( attributeName, clazz ) );
    }
      
    

這四個(gè)重載方法都調(diào)用了addRule()方法,ObjectCreateRule類是Rule類的子類,該類的實(shí)例可作為addRule()方法的第二個(gè)參數(shù)使用。

下面是ObjectCreateRule類的begin()方法和end()方法的實(shí)現(xiàn)

      
         @Override
    
      
      
        public
      
      
        void
      
      
         begin( String namespace, String name, Attributes attributes )
        
      
      
        throws
      
      
         Exception
    {
        Class
      
      <?> clazz = 
      
        this
      
      
        .clazz;

        
      
      
        if
      
       ( clazz == 
      
        null
      
      
         )
        {
            
      
      
        //
      
      
         Identify the name of the class to instantiate
      
      
            String realClassName =
      
         className;
            
      
      
        if
      
       ( attributeName != 
      
        null
      
      
         )
            {
                String value 
      
      =
      
         attributes.getValue( attributeName );
                
      
      
        if
      
       ( value != 
      
        null
      
      
         )
                {
                    realClassName 
      
      =
      
         value;
                }
            }
            
      
      
        if
      
      
         ( getDigester().getLogger().isDebugEnabled() )
            {
                getDigester().getLogger().debug( format( 
      
      "[ObjectCreateRule]{%s} New '%s'"
      
        ,
                                                         getDigester().getMatch(),
                                                         realClassName ) );
            }

            
      
      
        //
      
      
         Instantiate the new object and push it on the context stack
      
      
            clazz =
      
         getDigester().getClassLoader().loadClass( realClassName );
        }
        Object instance;
        
      
      
        if
      
       ( constructorArgumentTypes == 
      
        null
      
       || constructorArgumentTypes.length == 0
      
         )
        {
            
      
      
        if
      
      
         ( getDigester().getLogger().isDebugEnabled() )
            {
                getDigester()
                    .getLogger()
                    .debug( format( 
      
      "[ObjectCreateRule]{%s} New '%s' using default empty constructor"
      
        ,
                                    getDigester().getMatch(),
                                    clazz.getName() ) );
            }

            instance 
      
      =
      
         clazz.newInstance();
        }
        
      
      
        else
      
      
        
        {
            
      
      
        if
      
       ( proxyManager == 
      
        null
      
      
         )
            {
                Constructor
      
      <?> constructor =
      
         getAccessibleConstructor( clazz, constructorArgumentTypes );

                
      
      
        if
      
       ( constructor == 
      
        null
      
      
         )
                {
                    
      
      
        throw
      
      
        new
      
      
         SAXException(
                                   format( 
      
      "[ObjectCreateRule]{%s} Class '%s' does not have a construcor with types %s"
      
        ,
                                           getDigester().getMatch(),
                                           clazz.getName(),
                                           Arrays.toString( constructorArgumentTypes ) ) );
                }
                proxyManager 
      
      = 
      
        new
      
      
         ProxyManager( clazz, constructor, defaultConstructorArguments, getDigester() );
            }
            instance 
      
      =
      
         proxyManager.createProxy();
        }
        getDigester().push( instance );
    }

    
      
      
        /**
      
      
        
     * {
      
      
        @inheritDoc
      
      
        }
     
      
      
        */
      
      
        
    @Override
    
      
      
        public
      
      
        void
      
      
         end( String namespace, String name )
        
      
      
        throws
      
      
         Exception
    {
        Object top 
      
      =
      
         getDigester().pop();

        
      
      
        if
      
       ( proxyManager != 
      
        null
      
      
         )
        {
            proxyManager.finalize( top );
        }

        
      
      
        if
      
      
         ( getDigester().getLogger().isDebugEnabled() )
        {
            getDigester().getLogger().debug( format( 
      
      "[ObjectCreateRule]{%s} Pop '%s'"
      
        ,
                                                     getDigester().getMatch(),
                                                     top.getClass().getName() ) );
        }
    }
      
    

begin()方法用于創(chuàng)建一個(gè)對(duì)象實(shí)例,并將其壓入到Digester對(duì)象的內(nèi)部棧中;end()方法會(huì)將內(nèi)部棧的棧頂元素彈出棧

要向Digester實(shí)例中添加Rule對(duì)象,還可以調(diào)用其addRuleSet()方法,方法實(shí)現(xiàn)如下:

      
        public
      
      
        void
      
      
         addRuleSet( RuleSet ruleSet )
    {
        String oldNamespaceURI 
      
      =
      
         getRuleNamespaceURI();
        String newNamespaceURI 
      
      =
      
         ruleSet.getNamespaceURI();
        
      
      
        if
      
      
         ( log.isDebugEnabled() )
        {
            
      
      
        if
      
       ( newNamespaceURI == 
      
        null
      
      
         )
            {
                log.debug( 
      
      "addRuleSet() with no namespace URI"
      
         );
            }
            
      
      
        else
      
      
        
            {
                log.debug( 
      
      "addRuleSet() with namespace URI " +
      
         newNamespaceURI );
            }
        }
        setRuleNamespaceURI( newNamespaceURI );
        
        
          ruleSet.addRuleInstances( 
        
      
      
        this
      
      
        
           );
        
        
        setRuleNamespaceURI( oldNamespaceURI );
    }
      
    

org.apache.commons.digester3.RuleSet接口表示Rule對(duì)象的集合,該接口定義了兩個(gè)方法,分別為addRuleInstance()和getNamespaceURI(),addRuleInstance()方法簽名如下:

public void addRuleInstance(Digester digester)

addRuleInstance()方法用于添加定義在當(dāng)前RuleSet對(duì)象中的Rule對(duì)象集合到作為該方法參數(shù)傳輸?shù)腄igester實(shí)例中

getNamespaceUR()方法返回將要應(yīng)用在所有Rule對(duì)象(在當(dāng)前Ruleset中創(chuàng)建的)的命名空間的URI,該方法簽名如下

public java.lang.String getNamespaceURI()

因此,在創(chuàng)建了Digester對(duì)象之后,可以創(chuàng)建一個(gè)RuleSet對(duì)象,并將其傳輸給Digester對(duì)象的addRuleSet()方法

為了便于使用,實(shí)現(xiàn)RuleSet接口有一個(gè)基類RuleSetBase,RuleSetBase類為抽象類,提供了getNamespaceURI()方法的實(shí)現(xiàn),我們只需要提供addRuleInstances()方法的實(shí)現(xiàn)就可以了

下面是我們創(chuàng)建的EmployeeRuleSet類的源碼(繼承自RuleSetBase類)

      
        public
      
      
        class
      
       EmployeeRuleSet 
      
        extends
      
      
         RuleSetBase  {
  
      
      
        public
      
      
        void
      
      
         addRuleInstances(Digester digester) {
    
      
      
        //
      
      
         add rules
      
      
    digester.addObjectCreate("employee", "ex15.pyrmont.digestertest.Employee"
      
        );
    digester.addSetProperties(
      
      "employee"
      
        );    
    digester.addObjectCreate(
      
      "employee/office", "ex15.pyrmont.digestertest.Office"
      
        );
    digester.addSetProperties(
      
      "employee/office"
      
        );
    digester.addSetNext(
      
      "employee/office", "addOffice"
      
        );
    digester.addObjectCreate(
      
      "employee/office/address"
      
        , 
      
      
      "ex15.pyrmont.digestertest.Address"
      
        );
    digester.addSetProperties(
      
      "employee/office/address"
      
        );
    digester.addSetNext(
      
      "employee/office/address", "setAddress"
      
        ); 
  }
}
      
    

我們注意到,EmployeeRuleSet類中的addRuleInstances()方法的實(shí)現(xiàn)的功能類似Test02類,將相同的Rule對(duì)象添加到Digester對(duì)象中

下面是Test03的代碼,里面會(huì)創(chuàng)建EmployeeRuleSet類的實(shí)例,然后將其添加到之前創(chuàng)建的Digester對(duì)象中

      
        public
      
      
        class
      
      
         Test03 {

  
      
      
        public
      
      
        static
      
      
        void
      
      
         main(String[] args) {
   
      
      
    InputStream inputStream = 
      
        null
      
      
        ;
    Digester digester 
      
      = 
      
        new
      
      
         Digester();
    digester.addRuleSet(
      
      
        new
      
      
         EmployeeRuleSet());
    
      
      
        try
      
      
         {
      inputStream 
      
      = Thread.currentThread().getContextClassLoader().getResourceAsStream("employee2.xml"
      
        );
      Employee employee 
      
      =
      
         (Employee) digester.parse(inputStream);
      ArrayList offices 
      
      =
      
         employee.getOffices();
      Iterator iterator 
      
      =
      
         offices.iterator();
      System.out.println(
      
      "-------------------------------------------------"
      
        );
      
      
      
        while
      
      
         (iterator.hasNext()) {
        Office office 
      
      =
      
         (Office) iterator.next();
        Address address 
      
      =
      
         office.getAddress();
        System.out.println(office.getDescription());
        System.out.println(
      
      "Address : " +
      
         
          address.getStreetNumber() 
      
      + " " +
      
         address.getStreetName());
        System.out.println(
      
      "--------------------------------"
      
        );
      }
      
    }
    
      
      
        catch
      
      
        (Exception e) {
      e.printStackTrace();
    }
    
      
      
        finally
      
      
         {
        
      
      
        if
      
       (inputStream != 
      
        null
      
      
        ) {
            
      
      
        try
      
      
         {
                inputStream.close();
            } 
      
      
        catch
      
      
         (IOException e) {
                
      
      
        //
      
      
         TODO Auto-generated catch block
      
      
                        e.printStackTrace();
            }
        }
    }
  }
}
      
    

與其他類型的容器不同,StandardContext實(shí)例必須有一個(gè)監(jiān)聽器,該監(jiān)聽器會(huì)負(fù)責(zé)配置StandardContext實(shí)例,設(shè)置成功后會(huì)將StandardContext實(shí)例的變量configued值設(shè)置為tue。

StandardContext類的標(biāo)準(zhǔn)監(jiān)聽器是org.apache.catalina.startup.ContextConfig類的實(shí)例,它會(huì)執(zhí)行很對(duì)StandardContext實(shí)例來說必不可少的任務(wù),例如安裝驗(yàn)證器閥到StandardContext實(shí)例的管道對(duì)象中,此外還會(huì)添加許可器閥(類型為org.apache.catalina.valves.CertificateValve)到管道對(duì)象中。

但更重要的是,ContextConfig類的實(shí)例還會(huì)讀取和解析默認(rèn)的web.xml文件和應(yīng)用程序自定義的web.xml文件,并將xml元素轉(zhuǎn)換為java對(duì)象。

默認(rèn)的web.xml文件位于CATALINE_HOME目錄下的conf目錄中,其中定義并映射了很多默認(rèn)的servlet,配置了很多MIME類型文件的映射,定義了默認(rèn)的session超時(shí)時(shí)間,以及定義了歡迎文件的列表。

應(yīng)用程序的web.xml文件是應(yīng)用程序自定義的配置文件,位于應(yīng)用程序目錄下的WEB-INF目錄中。

ContextConfig實(shí)例會(huì)為每一個(gè)servlet元素創(chuàng)建StandardWrapper實(shí)例,因此,正如你在本章應(yīng)用程序中看到的,配置變簡(jiǎn)單了,你不在需要實(shí)例化Wrapper實(shí)例了

因此,我們需要在Bootstrap類中實(shí)例化一個(gè)ContextConfig類,并調(diào)用org.apache.catalina.Lifecycle接口的addLifecycleListener()方法將其添加到StandardContext對(duì)象中

      LifecycleListener listener = 
      
        new
      
      
         ContextConfig();
((Lifecycle) context).addLifecycleListener(listener);
      
    

在啟動(dòng)和停止StandardContext實(shí)例時(shí),會(huì)觸發(fā)相應(yīng)事件,ContextConfig類會(huì)對(duì)兩種事件做出響應(yīng),分別為START_EVENT 和STOP_EVENT

每當(dāng)StandardContext實(shí)例觸發(fā)事件時(shí),會(huì)調(diào)用ContextConfig實(shí)例的lifecycleEvent()方法

      
        public
      
      
        void
      
      
         lifecycleEvent(LifecycleEvent event) {

        
      
      
        //
      
      
         Identify the context we are associated with
      
      
        try
      
      
         {
            context 
      
      =
      
         (Context) event.getLifecycle();
            
      
      
        if
      
       (context 
      
        instanceof
      
      
         StandardContext) {
                
      
      
        int
      
       contextDebug =
      
         ((StandardContext) context).getDebug();
                
      
      
        if
      
       (contextDebug > 
      
        this
      
      
        .debug)
                    
      
      
        this
      
      .debug =
      
         contextDebug;
            }
        } 
      
      
        catch
      
      
         (ClassCastException e) {
            log(sm.getString(
      
      "contextConfig.cce"
      
        , event.getLifecycle()), e);
            
      
      
        return
      
      
        ;
        }

        
      
      
        //
      
      
         Process the event that has occurred
      
      
        if
      
      
         (event.getType().equals(Lifecycle.START_EVENT))
            start();
        
      
      
        else
      
      
        if
      
      
         (event.getType().equals(Lifecycle.STOP_EVENT))
            stop();

    }
      
    

在上面方法中,會(huì)繼續(xù)調(diào)用start()方法和stop()方法

      
        private
      
      
        synchronized
      
      
        void
      
      
         start() {

        
      
      
        if
      
       (debug > 0
      
        )
            log(sm.getString(
      
      "contextConfig.start"
      
        ));
        context.setConfigured(
      
      
        false
      
      
        );
        ok 
      
      = 
      
        true
      
      
        ;

        
      
      
        //
      
      
         Set properties based on DefaultContext
      
      
        Container container =
      
         context.getParent();
        
      
      
        if
      
      ( !
      
        context.getOverride() ) {
            
      
      
        if
      
      ( container 
      
        instanceof
      
      
         Host ) {
                ((Host)container).importDefaultContext(context);
                container 
      
      =
      
         container.getParent();
            }
            
      
      
        if
      
      ( container 
      
        instanceof
      
      
         Engine ) {
                ((Engine)container).importDefaultContext(context);
            }
        }

        
      
      
        //
      
      
         Process the default and application web.xml files
      
      
                defaultConfig();
        applicationConfig();
        
      
      
        if
      
      
         (ok) {
            validateSecurityRoles();
        }

        
      
      
        //
      
      
         Scan tag library descriptor files for additional listener classes
      
      
        if
      
      
         (ok) {
            
      
      
        try
      
      
         {
                tldScan();
            } 
      
      
        catch
      
      
         (Exception e) {
                log(e.getMessage(), e);
                ok 
      
      = 
      
        false
      
      
        ;
            }
        }

        
      
      
        //
      
      
         Configure a certificates exposer valve, if required
      
      
        if
      
      
         (ok)
            certificatesConfig();

        
      
      
        //
      
      
         Configure an authenticator if we need one
      
      
        if
      
      
         (ok)
            authenticatorConfig();

        
      
      
        //
      
      
         Dump the contents of this pipeline if requested
      
      
        if
      
       ((debug >= 1) && (context 
      
        instanceof
      
      
         ContainerBase)) {
            log(
      
      "Pipline Configuration:"
      
        );
            Pipeline pipeline 
      
      =
      
         ((ContainerBase) context).getPipeline();
            Valve valves[] 
      
      = 
      
        null
      
      
        ;
            
      
      
        if
      
       (pipeline != 
      
        null
      
      
        )
                valves 
      
      =
      
         pipeline.getValves();
            
      
      
        if
      
       (valves != 
      
        null
      
      
        ) {
                
      
      
        for
      
       (
      
        int
      
       i = 0; i < valves.length; i++
      
        ) {
                    log(
      
      "  " +
      
         valves[i].getInfo());
                }
            }
            log(
      
      "======================"
      
        );
        }

        
      
      
        //
      
      
         Make our application available if no problems were encountered
      
      
        if
      
      
         (ok)
            context.setConfigured(
      
      
        true
      
      
        );
        
      
      
        else
      
      
         {
            log(sm.getString(
      
      "contextConfig.unavailable"
      
        ));
            context.setConfigured(
      
      
        false
      
      
        );
        }

    }
      
    

start()方法會(huì)進(jìn)一步調(diào)用defaultConfig()方法和applicationConfig()方法

defaultConfig()方法負(fù)責(zé)讀取并解析位于%CATALINA_HOME%/conf目錄下的默認(rèn)的web.xml文件

      
        private
      
      
        void
      
      
         defaultConfig() {

        
      
      
        //
      
      
         Open the default web.xml file, if it exists
      
      
        File file = 
      
        new
      
      
         File(Constants.DefaultWebXml);
        
      
      
        if
      
       (!
      
        file.isAbsolute())
            file 
      
      = 
      
        new
      
       File(System.getProperty("catalina.base"
      
        ),
                            Constants.DefaultWebXml);
        FileInputStream stream 
      
      = 
      
        null
      
      
        ;
        
      
      
        try
      
      
         {
            stream 
      
      = 
      
        new
      
      
         FileInputStream(file.getCanonicalPath());
            stream.close();
            stream 
      
      = 
      
        null
      
      
        ;
        } 
      
      
        catch
      
      
         (FileNotFoundException e) {
            log(sm.getString(
      
      "contextConfig.defaultMissing"
      
        ));
            
      
      
        return
      
      
        ;
        } 
      
      
        catch
      
      
         (IOException e) {
            log(sm.getString(
      
      "contextConfig.defaultMissing"
      
        ), e);
            
      
      
        return
      
      
        ;
        }

        
      
      
        //
      
      
         Process the default web.xml file
      
      
        synchronized
      
      
         (webDigester) {
            
      
      
        try
      
      
         {
                InputSource is 
      
      =
                    
      
        new
      
       InputSource("file://" +
      
         file.getAbsolutePath());
                stream 
      
      = 
      
        new
      
      
         FileInputStream(file);
                is.setByteStream(stream);
                webDigester.setDebug(getDebug());
                
      
      
        if
      
       (context 
      
        instanceof
      
      
         StandardContext)
                    ((StandardContext) context).setReplaceWelcomeFiles(
      
      
        true
      
      
        );
                webDigester.clear();
                webDigester.push(context);
                webDigester.parse(is);
            } 
      
      
        catch
      
      
         (SAXParseException e) {
                log(sm.getString(
      
      "contextConfig.defaultParse"
      
        ), e);
                log(sm.getString(
      
      "contextConfig.defaultPosition"
      
        ,
                                 
      
      "" +
      
         e.getLineNumber(),
                                 
      
      "" +
      
         e.getColumnNumber()));
                ok 
      
      = 
      
        false
      
      
        ;
            } 
      
      
        catch
      
      
         (Exception e) {
                log(sm.getString(
      
      "contextConfig.defaultParse"
      
        ), e);
                ok 
      
      = 
      
        false
      
      
        ;
            } 
      
      
        finally
      
      
         {
                
      
      
        try
      
      
         {
                    
      
      
        if
      
       (stream != 
      
        null
      
      
        ) {
                        stream.close();
                    }
                } 
      
      
        catch
      
      
         (IOException e) {
                    log(sm.getString(
      
      "contextConfig.defaultClose"
      
        ), e);
                }
            }
        }

    }
      
    

applicationConfig()方法與defaultConfig()方法類似,只不過它處理的是應(yīng)用程序自定義的部署描述符,該部署描述符位于應(yīng)用目錄下的WEB-INF目錄中

      
        private
      
      
        void
      
      
         applicationConfig() {

        
      
      
        //
      
      
         Open the application web.xml file, if it exists
      
      
        InputStream stream = 
      
        null
      
      
        ;
        ServletContext servletContext 
      
      =
      
         context.getServletContext();
        
      
      
        if
      
       (servletContext != 
      
        null
      
      
        )
            stream 
      
      =
      
         servletContext.getResourceAsStream
                (Constants.ApplicationWebXml);
        
      
      
        if
      
       (stream == 
      
        null
      
      
        ) {
            log(sm.getString(
      
      "contextConfig.applicationMissing"
      
        ));
            
      
      
        return
      
      
        ;
        }

        
      
      
        //
      
      
         Process the application web.xml file
      
      
        synchronized
      
      
         (webDigester) {
            
      
      
        try
      
      
         {
                URL url 
      
      =
      
        
                    servletContext.getResource(Constants.ApplicationWebXml);

                InputSource is 
      
      = 
      
        new
      
      
         InputSource(url.toExternalForm());
                is.setByteStream(stream);
                webDigester.setDebug(getDebug());
                
      
      
        if
      
       (context 
      
        instanceof
      
      
         StandardContext) {
                    ((StandardContext) context).setReplaceWelcomeFiles(
      
      
        true
      
      
        );
                }
                webDigester.clear();
                webDigester.push(context);
                webDigester.parse(is);
            } 
      
      
        catch
      
      
         (SAXParseException e) {
                log(sm.getString(
      
      "contextConfig.applicationParse"
      
        ), e);
                log(sm.getString(
      
      "contextConfig.applicationPosition"
      
        ,
                                 
      
      "" +
      
         e.getLineNumber(),
                                 
      
      "" +
      
         e.getColumnNumber()));
                ok 
      
      = 
      
        false
      
      
        ;
            } 
      
      
        catch
      
      
         (Exception e) {
                log(sm.getString(
      
      "contextConfig.applicationParse"
      
        ), e);
                ok 
      
      = 
      
        false
      
      
        ;
            } 
      
      
        finally
      
      
         {
                
      
      
        try
      
      
         {
                    
      
      
        if
      
       (stream != 
      
        null
      
      
        ) {
                        stream.close();
                    }
                } 
      
      
        catch
      
      
         (IOException e) {
                    log(sm.getString(
      
      "contextConfig.applicationClose"
      
        ), e);
                }
            }
        }

    }
      
    

在ContextConfig類中,使用變量webDigester來引用一個(gè)Digester類型的對(duì)象

private static Digester webDigester = createWebDigester();

該Digester對(duì)象用于解析默認(rèn)的web.xml文件和應(yīng)用程序自定義的web.xml文件,在調(diào)用createWebDigester()方法時(shí)會(huì)添加用來處理web.xml文件的規(guī)則

      
        /**
      
      
        
     * Create (if necessary) and return a Digester configured to process the
     * web application deployment descriptor (web.xml).
     
      
      
        */
      
      
        private
      
      
        static
      
      
         Digester createWebDigester() {

        URL url 
      
      = 
      
        null
      
      
        ;
        Digester webDigester 
      
      = 
      
        new
      
      
         Digester();
        webDigester.setValidating(
      
      
        true
      
      
        );
        url 
      
      = ContextConfig.
      
        class
      
      
        .getResource(Constants.WebDtdResourcePath_22);
        webDigester.register(Constants.WebDtdPublicId_22,
                             url.toString());
        url 
      
      = ContextConfig.
      
        class
      
      
        .getResource(Constants.WebDtdResourcePath_23);
        webDigester.register(Constants.WebDtdPublicId_23,
                             url.toString());
       
        
           webDigester.addRuleSet(
        
      
      
        new WebRuleSet());
        
      
      
        return
      
      
         (webDigester);

    }
      
    

我們注意到,上面方法中調(diào)用了變量webDigester的addRuleSet()方法,傳入一個(gè)org.apache.catalina.startup.WebRuleSet類型的對(duì)象作為參數(shù);WebRuleSet類是org.apache.commons.digester.RuleSetBase的子類。

下面是WebRuleSet類的addRuleInstances()方法實(shí)現(xiàn):

      
        public
      
      
        void
      
      
         addRuleInstances(Digester digester) {

        digester.addRule(prefix 
      
      + "web-app"
      
        ,
                         
      
      
        new
      
       SetPublicIdRule(digester, "setPublicId"
      
        ));

        digester.addCallMethod(prefix 
      
      + "web-app/context-param"
      
        ,
                               
      
      "addParameter", 2
      
        );
        digester.addCallParam(prefix 
      
      + "web-app/context-param/param-name", 0
      
        );
        digester.addCallParam(prefix 
      
      + "web-app/context-param/param-value", 1
      
        );

        digester.addCallMethod(prefix 
      
      + "web-app/display-name"
      
        ,
                               
      
      "setDisplayName", 0
      
        );

        digester.addRule(prefix 
      
      + "web-app/distributable"
      
        ,
                         
      
      
        new
      
      
         SetDistributableRule(digester));

        digester.addObjectCreate(prefix 
      
      + "web-app/ejb-local-ref"
      
        ,
                                 
      
      "org.apache.catalina.deploy.ContextLocalEjb"
      
        );
        digester.addSetNext(prefix 
      
      + "web-app/ejb-local-ref"
      
        ,
                            
      
      "addLocalEjb"
      
        ,
                            
      
      "org.apache.catalina.deploy.ContextLocalEjb"
      
        );

        
      
      
        //
      
      
        代碼太長,后面部分略
      
      
        
    }
      
    

---------------------------------------------------------------------------?

本系列How Tomcat Works系本人原創(chuàng)?

轉(zhuǎn)載請(qǐng)注明出處 博客園 刺猬的溫馴?

本人郵箱: ? chenying998179 # 163.com ( #改為@

本文鏈接 http://www.cnblogs.com/chenying99/p/3249161.html

How Tomcat Works(十八)


更多文章、技術(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)論
主站蜘蛛池模板: 三穗县| 喀喇沁旗| 白沙| 大庆市| 土默特左旗| 嘉荫县| 阜宁县| 民县| 武城县| 霍山县| 澜沧| 香格里拉县| 清流县| 和政县| 华容县| 鄯善县| 慈利县| 江安县| 页游| 丰镇市| 垦利县| 瑞丽市| 吉木萨尔县| 三门县| 武夷山市| 阿克陶县| 宁城县| 房产| 尚义县| 且末县| 道孚县| 隆安县| 漳平市| 临漳县| 彭山县| 龙游县| 买车| 新和县| 遂昌县| 炉霍县| 固阳县|