How Tomcat Works(十八)

系统 1656 0

在前面的文章中,如果我们要启动tomcat容器,我们需要使用Bootstrap类来实例化连接器、servlet容器、Wrapper实例和其他组件,然后调用各个对象的set方法将它们关联起来;这种配置应用程序的方法有一个明显的缺陷,即所有的配置都必须硬编码。调整组件配置和属性值都必须要重新编译Bootstrap类。幸运的是,Tomcat的设计者使用了一种更加优雅的配置方式,即使用一个名为server.xml的XML文件来对应用程序进行配置。server.xml文件中的每个元素都会转换为一个java对象,元素的属性会用于设置java对象的属性,这样,就可以通过简单的编辑server.xml文件来修改tomcat的配置。

Tomcat使用了开源库Digester来将xml文件中的元素转换成java对象。

由于一个Context实例表示一个Web应用程序,因此配置Web应用程序是通过对已经实例化的Context实例进行配置完成的。用来配置Web应用程序的XML文件的名称是web.xml,该文件位于Web应用程序的WEB-INF目录下。

下面来介绍Digester库,Digester库是Apache软件基金会的Jatarta项目下的子Commons项目下的一个开源项目,它的主页地址是http://commons.apache.org/proper/commons-digester/

org.apache.commons.digester3.Digester类是Digester库中的主类,该类可用于解析XML文件,对于XML文件中的每个元素,Digester对象都会检查它是否要做事先预定义的事件,在调用Digester对象的parse()方法之前,程序员要先定义好Digester对象执行哪些动作。

因此,程序员要先定义好模式,然后将每个模式与一条或多条规则相关联。

模式通常是xml文件里面元素的路径,类似于xpath的语法路径

规则指明了当Digester对象遇到了某个特殊的模式时要执行的一个或多个动作,规则是org.apache.commons.digester3.Rule类的实例,Digester类开源包含0个或多个Rule对象,在Digester实例中,这些规则和其相关联的模式都存储在由org.apache.commons.digester3.Rules接口表示的一类存储器中,每当把一条规则添加到Digester实例中时,Rule对象都会被添加到Rules对象中。

另外,Rule类有begin()方法和end()方法,在解析xml文件时,当Digester实例遇到匹配某个模式的元素的开始标签时,它会调用相应的Rule对象的begin()方法,而当Digester实例遇到相应元素的结束标签时,它会调用Rule对象的end()方法。

在使用Digester库时,我们需要先导入相关依赖jar

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

第一个示例应用程序演示如何使用Digester库动态的创建对象,并设置相应的属性值。

employee1.xml文件内容如下

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

我们需要根据上面的xml文件创建Employee对象,并设置相应属性,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);
  }
}
      
    

现在写一个测试类Test01,它使用Digester类,并为其添加创建Employee对象和设置其属性的规则。

      
        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();
                }
            }
        }
    }

}
      
    

第二个示例演示如何利用Digester库创建两个对象,并建立他们之间的关系

employee2.xml 文件内容如下

      
        <?
      
      
        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
      
      
        >
      
    

然后我们还需要创建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类的定义,该类使用一个Digester对象,并为其添加规则

      
        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类包含了一些方法,其中最重要的两个方法是begin()方法和end()方法,当Digester实例遇到某个XML元素的开始标签时,它会调用它所包含的匹配Rule对象的begin()方法,方法签名如下:

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

当Digester实例遇到某个XML元素的结束标签时,它会调用它所包含的匹配Rule对象的end()方法,方法签名如下:

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

Digester对象是如何完成这些工作的呢?当调用Digester对象的addObjectCreate()方法、addCallMethod()方法、addSetNext()方法或其他方法时,都会间接地调用Digester类的addRule()方法;该方法将一个Rule对象和它所匹配的模式添加到Digester对象的Rules集合中。

addRule()方法实现如下:

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

查看Digester类的addObjectCreate()方法的重载实现如下:

      
        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 ) );
    }
      
    

这四个重载方法都调用了addRule()方法,ObjectCreateRule类是Rule类的子类,该类的实例可作为addRule()方法的第二个参数使用。

下面是ObjectCreateRule类的begin()方法和end()方法的实现

      
         @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()方法用于创建一个对象实例,并将其压入到Digester对象的内部栈中;end()方法会将内部栈的栈顶元素弹出栈

要向Digester实例中添加Rule对象,还可以调用其addRuleSet()方法,方法实现如下:

      
        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对象的集合,该接口定义了两个方法,分别为addRuleInstance()和getNamespaceURI(),addRuleInstance()方法签名如下:

public void addRuleInstance(Digester digester)

addRuleInstance()方法用于添加定义在当前RuleSet对象中的Rule对象集合到作为该方法参数传输的Digester实例中

getNamespaceUR()方法返回将要应用在所有Rule对象(在当前Ruleset中创建的)的命名空间的URI,该方法签名如下

public java.lang.String getNamespaceURI()

因此,在创建了Digester对象之后,可以创建一个RuleSet对象,并将其传输给Digester对象的addRuleSet()方法

为了便于使用,实现RuleSet接口有一个基类RuleSetBase,RuleSetBase类为抽象类,提供了getNamespaceURI()方法的实现,我们只需要提供addRuleInstances()方法的实现就可以了

下面是我们创建的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()方法的实现的功能类似Test02类,将相同的Rule对象添加到Digester对象中

下面是Test03的代码,里面会创建EmployeeRuleSet类的实例,然后将其添加到之前创建的Digester对象中

      
        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实例必须有一个监听器,该监听器会负责配置StandardContext实例,设置成功后会将StandardContext实例的变量configued值设置为tue。

StandardContext类的标准监听器是org.apache.catalina.startup.ContextConfig类的实例,它会执行很对StandardContext实例来说必不可少的任务,例如安装验证器阀到StandardContext实例的管道对象中,此外还会添加许可器阀(类型为org.apache.catalina.valves.CertificateValve)到管道对象中。

但更重要的是,ContextConfig类的实例还会读取和解析默认的web.xml文件和应用程序自定义的web.xml文件,并将xml元素转换为java对象。

默认的web.xml文件位于CATALINE_HOME目录下的conf目录中,其中定义并映射了很多默认的servlet,配置了很多MIME类型文件的映射,定义了默认的session超时时间,以及定义了欢迎文件的列表。

应用程序的web.xml文件是应用程序自定义的配置文件,位于应用程序目录下的WEB-INF目录中。

ContextConfig实例会为每一个servlet元素创建StandardWrapper实例,因此,正如你在本章应用程序中看到的,配置变简单了,你不在需要实例化Wrapper实例了

因此,我们需要在Bootstrap类中实例化一个ContextConfig类,并调用org.apache.catalina.Lifecycle接口的addLifecycleListener()方法将其添加到StandardContext对象中

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

在启动和停止StandardContext实例时,会触发相应事件,ContextConfig类会对两种事件做出响应,分别为START_EVENT 和STOP_EVENT

每当StandardContext实例触发事件时,会调用ContextConfig实例的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();

    }
      
    

在上面方法中,会继续调用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()方法会进一步调用defaultConfig()方法和applicationConfig()方法

defaultConfig()方法负责读取并解析位于%CATALINA_HOME%/conf目录下的默认的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()方法类似,只不过它处理的是应用程序自定义的部署描述符,该部署描述符位于应用目录下的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来引用一个Digester类型的对象

private static Digester webDigester = createWebDigester();

该Digester对象用于解析默认的web.xml文件和应用程序自定义的web.xml文件,在调用createWebDigester()方法时会添加用来处理web.xml文件的规则

      
        /**
      
      
        
     * 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);

    }
      
    

我们注意到,上面方法中调用了变量webDigester的addRuleSet()方法,传入一个org.apache.catalina.startup.WebRuleSet类型的对象作为参数;WebRuleSet类是org.apache.commons.digester.RuleSetBase的子类。

下面是WebRuleSet类的addRuleInstances()方法实现:

      
        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系本人原创 

转载请注明出处 博客园 刺猬的温驯 

本人邮箱:   chenying998179 # 163.com ( #改为@

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

How Tomcat Works(十八)


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论