您的位置:首页 > 运维架构 > Tomcat

tomcat源码研读笔记—tomcat的启动之三 StandardEngine的启动

2018-03-21 17:31 696 查看
这一章节开始,我们进入了所谓的“容器”内部了,standardEngine启动的源码如下:
   public void start() throws LifecycleException {
       // Log our server identification information
       System.out.println(ServerInfo.getServerInfo());
       // Standard container startup
       super.start();
}
 
可以知道,standardEngine直接将启动传递给了父类,我们看下standardEngine的继承关系:



1,standardEngine实现了Engine接口,同时继承了ContainerBase
2,ContainerBase实现了Lifecycle,Container和Pipeline接口
 
根据上边类的继承关系,我们进入ContainerBase内的start方法:
publicsynchronized void start() throws LifecycleException {
 
        // Validate and update our currentcomponent state
        if (started)
            throw new LifecycleException
               (sm.getString("containerBase.alreadyStarted", logName()));
 
        // Notify our interestedLifecycleListeners
        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT,null);
 
        addDefaultMapper(this.mapperClass);
        started = true;
 
        // Start our subordinate components, ifany
        if ((loader != null) && (loaderinstanceof Lifecycle))
            ((Lifecycle) loader).start();
        if ((logger != null) && (loggerinstanceof Lifecycle))
            ((Lifecycle) logger).start();
        if ((manager != null) &&(manager instanceof Lifecycle))
            ((Lifecycle) manager).start();
        if ((cluster != null) &&(cluster instanceof Lifecycle))
            ((Lifecycle) cluster).start();
        if ((realm != null) && (realminstanceof Lifecycle))
            ((Lifecycle) realm).start();
        if ((resources != null) &&(resources instanceof Lifecycle))
            ((Lifecycle) resources).start();
 
        // Start our Mappers, if any
        Mapper mappers[] = findMappers();
        for (int i = 0; i < mappers.length;i++) {
            if (mappers[i] instanceofLifecycle)
                ((Lifecycle)mappers[i]).start();
        }
 
        // Start our child containers, if any
        Container children[] = findChildren();
        for (int i = 0; i < children.length;i++) {
            if (children[i] instanceofLifecycle)
                ((Lifecycle)children[i]).start();
        }
 
        // Start the Valves in our pipeline(including the basic), if any
        if (pipeline instanceof Lifecycle)
            ((Lifecycle) pipeline).start();
 
        // Notify our interestedLifecycleListeners
       lifecycle.fireLifecycleEvent(START_EVENT, null);
 
        // Notify our interestedLifecycleListeners
       lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
 
    }
 
根据源码我们分析如下几点重要的地方:
1,  这里也采用了上边的监听者模式,执行监听者的监听事件,我们根据之前规律,查看Catalina中的Digester机制,从EngineRuleSet中获取到LifeCycleListener的实现类是EngineConfig
2,  从addDefaultMapper方法的参数mapperClass,可以知道StandardEngineMapper被添加到mappers的HashMap集合中
3,  根据Digester机制 获取loader,logger,manager,cluster,realm,resources接口的实现类,并执行对应的start方法,当然这些实现类必须实现了Lifecycle,同时这些属性的对象也不能为空
4,  获取Mappers集合里边的对象,判断是否实现了Lifecycle接口,如实现了,那么执行start方法
5,  根据Digester机制获取子容器children集合,判断子容器是否实现了lifecycle接口,如实现了,那么将执行子容器的start方法
6,  执行管道属性pipeline中的start方法
 
 
第一,根据我们之前分析的监听者模式可以知道,最后调用的其实就是实现了LifeCycleListener接口实现类EngineConfig的lifecycleEvent方法,源码如下:
public voidlifecycleEvent(LifecycleEvent event) {
 
        // Identify the engine we areassociated with
        try {
            engine = (Engine)event.getLifecycle();
            if (engine instanceofStandardEngine) {
                int engineDebug = ((StandardEngine)engine).getDebug();
                if (engineDebug >this.debug)
                    this.debug = engineDebug;
            }
        } catch (ClassCastException e) {
           log(sm.getString("engineConfig.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();
 
    }
 
这儿方法做了一个判断,判断当前监听事件的被监听者是否是Egine接口的实现类,如果是,那么往下执行,同时判断是否是启动事件,如果是启动事件那么就调用自身的start方法,具体源码:
private voidstart() {
 
        if (debug > 0)
           log(sm.getString("engineConfig.start"));
 
    }
 
 只是打印了下记录就什么也没做,监听事件就执行完了。
 
第二,那么接下来我们查看的是addDefaultMapper方法,因这里讲this.mapperClass作为参数传递到方法体里边了,我从standardEngine的源码上可以知道,这个this.mapperClass,其实就是:StandardEngineMapper
 private String mapperClass =
       "org.apache.catalina.core.StandardEngineMapper";
 
而addDefaultMapper的方法体中我们查看源码如下:
protected void addDefaultMapper(StringmapperClass) {
 
       // Do we need a default Mapper?
       if (mapperClass == null)
           return;
       if (mappers.size() >= 1)
           return;
 
       // Instantiate and add a default Mapper
       try {
           Class clazz = Class.forName(mapperClass);
           Mapper mapper = (Mapper) clazz.newInstance();
           mapper.setProtocol("http");
           addMapper(mapper);
       } catch (Exception e) {
           log(sm.getString("containerBase.addDefaultMapper",mapperClass),
                e);
       }
 
}
将StandardEngineMapper加载到内存中,并实例化一个对象,并为对象赋值,如:mapper.setProtocol("http"),然后通过addMapper将这个对象往下传递:
 
public voidaddMapper(Mapper mapper) {
 
        synchronized(mappers) {
            if (mappers.get(mapper.getProtocol())!= null)
                throw newIllegalArgumentException("addMapper: Protocol '" +
                                                  mapper.getProtocol() +
                                                  "' is not unique");
  
4000
          mapper.setContainer((Container)this);      // May throw IAE
            if (started && (mapperinstanceof Lifecycle)) {
                try {
                    ((Lifecycle)mapper).start();
                } catch (LifecycleException e){
                   log("ContainerBase.addMapper: start: ", e);
                    throw newIllegalStateException
                       ("ContainerBase.addMapper: start: " + e);
                }
            }
            mappers.put(mapper.getProtocol(),mapper);
            if (mappers.size() == 1)
                this.mapper = mapper;
            else
                this.mapper = null;
           fireContainerEvent(ADD_MAPPER_EVENT, mapper);
        }
 
    }
 
如果mapper的Protocol属性不为空,在之前我们知道,这里设置了为http,所以不为空,那么将为mapper设置容器为当前对象,即为standardEngine; 接下来判断如果mapper实现了lifecycle接口那么将执行start方法,如果没有实现,那么以hashMap的key-value的方式放入mappers对象中,这里是http- StandardEngineMapper
 
  第三点,我们这里暂时不做深入了解,目前只知道有这些操作,等主线分析完了之后,我们再回过头来了解细节
 
   第四点,根据上边的分析,我们知道Mappers里边的StandardEngineMapper并没有实现lifecycle接口,所以,这段代码也跳过
 
   第五点,我们进入findChildren方法里边查看源码:
public Container[] findChildren() {
       synchronized (children) {
           Container results[] = new Container[children.size()];
           return ((Container[]) children.values().toArray(results));
       }
    }
 
发现这里其实就是获取children集合的一个hashMap而已,根据编码开闭原则,我们可以知道,这个类里边必定有往这个hashMap增加元素的方法:
 
private void addChildInternal(Containerchild) {
 
       synchronized(children) {
           if (children.get(child.getName()) != null)
                throw newIllegalArgumentException("addChild: Child name '" +
                                                  child.getName() +
                                                  "' is not unique");
           child.setParent((Container) this); // May throw IAE
           if (started && (child instanceof Lifecycle)) {
                try {
                    ((Lifecycle)child).start();
                } catch (LifecycleException e){
                   log("ContainerBase.addChild: start: ", e);
                    throw newIllegalStateException
                       ("ContainerBase.addChild: start: " + e);
               }
           }
           children.put(child.getName(), child);
           fireContainerEvent(ADD_CHILD_EVENT, child);
       }
 
}
 
我们查看这个方法发现是private修饰的,我们还发现这个内里边还有一个addChild方法调了它:
public voidaddChild(Container child) {
        if (System.getSecurityManager() !=null) {
            PrivilegedAction dp =
                new PrivilegedAddChild(child);
            AccessController.doPrivileged(dp);
        } else {
            addChildInternal(child);
        }
    }
 
这个方法是public进行修饰的,但是那个地方调用就了这个方法呢?这个时候,我们又得联想到server.xml的文档结构了,然后再查找Catalina中的代码:
digester.addRuleSet(newHostRuleSet("Server/Service/Engine/"));
 
然后再查看HostRuleSet中的addRuleInstances源码:
digester.addObjectCreate(prefix+ "Host",
                                 "org.apache.catalina.core.StandardHost",
                                "className");
        digester.addSetProperties(prefix +"Host");
        digester.addRule(prefix +"Host",
                         newCopyParentClassLoaderRule(digester));
        digester.addRule(prefix +"Host",
                         newLifecycleListenerRule
                         (digester,
                         "org.apache.catalina.startup.HostConfig",
                         "hostConfigClass"));
        digester.addSetNext(prefix +"Host",
                           "addChild",
                           "org.apache.catalina.Container");
 
这个时候,我们就明白了,原来children里边存着StandardHost对象集合,所以这里有将standardEngine的启动传递给了standardHost对象了
 
第6点,我们查看pipeline属性代码可以知道:
protectedPipeline pipeline = new StandardPipeline(this);
 
初始化的时候就讲pipeline赋值了一个StandardPipeline对象,同时将standardEngine作为构造参数传入到对象中,这个地方我们要注意下,在standardEngine的构造方法其实对pipeline进行了一些属性赋值:
 public StandardEngine() {
       super();
       pipeline.setBasic(new StandardEngineValve());
}
 
我们可以根据digester解析xml的机制,创建standardEngine的时候,就已经为pipeline的basic设置了StandardEngineValve对象,但是根据StandardEngineValve的继承关系,我们只到其实并没有实现lifecycle接口,所以就不执行start方法
 
  分析完了之后,我们来个小综述:
1,  standardEngine的start法其实是调用了父类containerBase的start方法
2,  containerBase的start方法,利用监听者模式,执行了监听者EngineConfig的监听方法
3,  设置了mappers的值为StandardEngineMapper
利用digester机制,为child增加了standardHost对象,并将standardEngine的start方法传递给了standardHost

standardEngine启动流程图如下:



standardEngine启动关系类图如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: