Tomcat源码阅读之Load过程

tomcat的load过程是从Bootstrap类的load方法开始的。load方法通过反射调用Catalina类的load方法。整个load过程主要有两条主线,一条主线是利用Digester的方式实例化容器组件,另一条主线是根据容器组件等级关系,由父组件到子组件进行逐级初始化。容器组件等级请查看tomcat组成图。
那么首先阅读Digester实例化容器组件部分的源码。

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
        digester.addObjectCreate("Server",
                                 "org.apache.catalina.core.StandardServer",
                                 "className");
        digester.addSetProperties("Server");
        digester.addSetNext("Server",
                            "setServer",
                            "org.apache.catalina.Server");

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

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

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

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

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

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


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




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

        // Add RuleSets for nested elements
        digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));
        digester.addRuleSet(new EngineRuleSet("Server/Service/"));
        digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
        digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
        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);

    }

Digester相关的语法这里就不多讲了,有兴趣的同学可以自行研究下,网上资料也是蛮多的。createStartDigester方法首先实例化的组件是Server组件,也就是服务器组件。服务器组件的接口是Server接口,标准实现类是StandardServer。实例化服务器组件的过程中将ServerFactory类的server属性设置成StandardServer类。因为StandardServer实现了Lifecycle接口,因此StandardServer中也实现了跟生命周期相关的方法,包括start和stop方法。
接着实例化服务组件,服务组件是Service接口的的实例,标准实现类是StandardService。实例化服务组件之后会调用StandardServer的addService方法,并且在addService方法中,会将服务组件的server属性设置为StandardServer,实现Service和Server的关联。StandardServer中有一个services数组,用来存放服务组件,从这儿也看出一个服务器组件可以对应多个服务组件。既然有增加服务组件的方法,自然就应该有removeService和findServices方法,作用就是删除和查找service。回到createStartDigester方法继续往下看,因为StandardService也实现了Lifecycle接口,因此服务组件的启动和停止等生命周期相关的活动均有其父组件统一管理,或者说由Tomcat容器统一管理,因为Tomcat容器是所有组件的父组件。那么父/子组件关系怎么区别呢?有两个方法,一个是根据tomcat结构图,越外围的,范围越大的就是父组件,而范围之内的就是其子组件,这个方法比较直观。还有一个方法就是根据createStartDigester中的规则,比如Server/Service/Connector这个规则,说明Server是service的父组件,service是Connector的父组件。
接着往下看,下一个实例化的组件是Connector组件,也叫连接器组件。

public Connector(String protocol)
        throws Exception {
        setProtocol(protocol);
        // Instantiate protocol handler
        try {
            Class clazz = Class.forName(protocolHandlerClassName);
            this.protocolHandler = (ProtocolHandler) clazz.newInstance();
        } catch (Exception e) {
            log.error
                (sm.getString
                 ("coyoteConnector.protocolHandlerInstantiationFailed", e));
        }
    }

在Connector的构造方法中完成了两件事,第一件是根据使用的通信协议设置处理类,默认处理类为Http11Protocol,跟使用协议为HTTP/1.1一样,可以认为默认使用的协议为HTTP/1.1。第二件是使用反射实例化协议处理类,设置连接超时时间和TCP_NODELAY。
实例完Connector之后,会调用StandardService类的addConnector方法,将已经实例化的Connector加入到一个Connector数组中,注意,是Connector数组,也就是说一个Tomcat服务器可以有多个用于通信的Connector。因为有多个连接器,因此Tomcat可以为多种不同的请求协议提供服务,例如一个连接器可以处理Http请求,而另一个可以处理Htpps请求。虽然addConnector方法中有connector.setContainer(this.container);这样一句代码,表面上看起来是将Connector和Container关联起来,但由于此时还没有实例化container容器,this.container的值为null,因此并未实现Connector和Container的关联。真正将这两个组件关联起来的地方是StandardService的setContainer方法,方法中有这样一句

for (int i = 0; i < connectors.length; i++)
      connectors[i].setContainer(this.container);

这句的作用是将Container容器跟所有的Connector关联起来,并且他们之间是一对多的关系,也就是说Tomcat中Connector可以有多个,但是Servlet容器只有一个,就是this.container。
Connector组件实现了Lifecycle接口,因此组件的初始化,start和stop等和生命周期相关的操作都有父组件控制。
接下来就该实例化Container组件了。未完待续。。。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值