[Tomcat6.0源码]强大的Digester

上回说到,Catalina的load方法,主要是创建Digester对象来解析conf/server.xml,以此来创建Server、Service等相关组件类。

关键步骤:

Digester digester = createStartDigester();
digester.push(this);
digester.parse(inputSource);

1.建立解析规则

2.将Catalina对象压栈

3.开始解析server.xml
 

先看看server.xml的结构(为方便阅读,删了些注释)

<?xml version='1.0' encoding='utf-8'?>
<Server port="8005" shutdown="SHUTDOWN">

  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <Listener className="org.apache.catalina.core.JasperListener" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />

  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>

  <Service name="Catalina">
  
    <Connector port="8080" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" />
    
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

    <Engine name="Catalina" defaultHost="localhost">

      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
             resourceName="UserDatabase"/>

      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true"
            xmlValidation="false" xmlNamespaceAware="false">
      </Host>
    </Engine>
  </Service>
</Server>


再对比Catalina.createStartDigester();

 

    protected Digester createStartDigester() {
        long t1=System.currentTimeMillis();
        // Initialize the digester
        Digester digester = new Digester();
        digester.setValidating(false);
        digester.setRulesValidation(true);
        HashMap<Class, List<String>> fakeAttributes = new HashMap<Class, List<String>>();
        ArrayList<String> attrs = new ArrayList<String>();
        attrs.add("className");
        fakeAttributes.put(Object.class, attrs);
        digester.setFakeAttributes(fakeAttributes);
        digester.setClassLoader(StandardServer.class.getClassLoader());

        // Configure the actions we will be using
        //解析conf/server.xml,当碰到Server节点时将创建StandardServer对象,并压栈。
        digester.addObjectCreate("Server",
                                 "org.apache.catalina.core.StandardServer",
                                 "className");
        //对Server节点的属性(如port、shutdown)将调用StandardServer的setter方法进行赋值
        digester.addSetProperties("Server");
        //碰到第二个Server节点,即</Server>,将弹出栈顶的StandardServer对象,
        //并作为新栈顶Catalina对象的setServer方法的参数,对其赋值
        //Catalina对象来自digester.push(this)
        //此时Catalina对象将持有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");
        //StandardServer对象、StandardService对象互相引用,server和service是一对多的关系
        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");

        //前面的addObjectCreate也是调用addRule来实现规则的保存
        //具体创建什么样类型的Connector,跟Connector节点的protocol的值有关系
        //见ConnectorCreateRule.begin();创建Connector对象:
        //Connector con = new Connector(attributes.getValue("protocol"));
        //server.xml中默认有两种类型HTTP/1.1、AJP/1.3
        digester.addRule("Server/Service/Connector",
                         new ConnectorCreateRule());
        digester.addRule("Server/Service/Connector", 
                         new SetAllPropertiesRule(new String[]{"executor"}));
        //Connector实例出栈时,作为Service.addConnector的参数
        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
        //RuleBaseSet的继承类都要实现addRuleInstances方法,方法中一般保存解析规则,
        //在digester.addRuleSet();调用此方法
        digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));
        /*将Engine实例赋值给StatandService对象的container*/
        digester.addRuleSet(new EngineRuleSet("Server/Service/"));
        
        /* 
         * StandardHost实例赋添加到StandardEngine实例的children中
         * 并给StandardHost实例添加监听器
         * */
        digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
        /* 
         * StandardContext实例赋添加到StandardHost实例的children中
         * 并给StandardContext实例添加监听器
         * */
        digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
        digester.addRuleSet(ClusterRuleSetFactory.getClusterRuleSet("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));
        digester.addRuleSet(ClusterRuleSetFactory.getClusterRuleSet("Server/Service/Engine/Cluster/"));

        long t2=System.currentTimeMillis();
        if (log.isDebugEnabled())
            log.debug("Digester for server.xml created " + ( t2-t1 ));
        return (digester);

    }

主要的类:Catalina持有 Server对象,Server对象持有Service对象(可能多个),Service对象持有Connector对象和Engine对象,Engine对象持有Host对象,Host对象持有Context对象。网上找了张图,比较直观点(http://www.360doc.com/content/10/0910/14/3200988_52628292.shtml):

这些对象间关系的建立,具体细节还需要再打开像addRuleSet这样方法才能探个究竟。

http://127.0.0.1:8080/test/main.jsp --> http://host:port/context/page.jsp

一个tomcat上要部署两个项目,并且host、port、context都不一样,那么必须配两组<service>节点

如果一个项目需要支持多个host、port、context只要一组<service>节点,然后配多组host、connector、context即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值