tomcat组件生命周期

时间:2021-01-01 09:00:02

版本:apache-tomcat-7.0.53

        Tomcat中组件都有各自的生命周期,从组件的初始化开始,到组件的销毁,在不同的生命周期阶段中,组件会完成不同的任务,每个阶段都对应一个状态,而状态的转换会触发相应的事件。

组件事件类型

组件状态

触发事件

事件编码值

说明

NEW

 

 

 

INITIALIZING

BEFORE_INIT_EVENT

before_init

代表组件初始化之前触发的事件

INITIALIZED

AFTER_INIT_EVENT

after_init

代表组件初始化之后触发的事件

STARTING

START_EVENT

start

组件正在开启时触发的事件

STARTING_PREP

BEFORE_START_EVENT

before_start

组件开启之前触发的事件

STARTED

AFTER_START_EVENT

after_start

组件开启之后触发的事件

STOPPING

STOP_EVENT

stop

组件正在停止时触发的事件

STOPPING_PREP

BEFORE_STOP_EVENT

before_stop

组件停止之前触发的事件

STOPPED

AFTER_STOP_EVENT

after_stop

组件停止之后触发的事件

DESTROYED

AFTER_DESTROY_EVENT

after_destroy

组件销毁之后触发的事件

DESTROYING

BEFORE_DESTROY_EVENT

before_destroy

组件销毁之前触发的事件

 

PERIODIC_EVENT

periodic

组件正在执行定期任务的时候触发的事件

STARTING

CONFIGURE_START_EVENT

configure_start

组件开始解析配置文件的时候触发的事件

STOPPING

CONFIGURE_STOP_EVENT

configure_stop

组件解析配置文件之后候触发的事件

FAILED

 

 

组件启动失败的状态

MUST_STOP

 

 

 

MUST_DESTROY

 

 

 

组件状态转换图

tomcat组件生命周期

        1、当该组件的start( )方法被调用,如果该组件的状态为NEW,程序会先调用该组件的init( )方法进行初始化工作,状态从NEW转换为INITIALIZING再到INITIALIZED,如果该组件已经初始化过了,调用start( )方法,状态直接为STARTING_PREP

        2、图中组件从一个状态到下一个状态,可以是调用该组件的某个方法,也可以是自动完成。比如图中INITIALIZED状态到STARTING_PREP状态,需要其他的组件调用该组件的start()方法;组件从STARTING_PREP状态到STARTING状态,这个过程是调用start()方法之后,组件内部自动完成的动作。

组件生命周期类图

        以下是以tomcat中StandardServer组件为例,画出该组件的类图。

 tomcat组件生命周期

        1、Lifecycle,该接口声明该组件支持哪些事件,以及为组件生命周期定义了一组公共的接口,组件类需要实现这些接口,这样可以为组件的生命周期中的开启和停止操作提供一种一致的机制。

        2、LifecycleBase,该类是Lifecycle接口的基本实现,对start()、stop()和destroy()方法提供了一组基础的实现,

        3、MBeanRegistration,该接口定义了一组接口,支持将对象注册到MBean server

        4、LifecycleMBeanBase,该抽象类继承了LifecycleBase类和实现了MBeanRegistration接口,表明该组件除了能够控制生命周期不同阶段外,还能将自身注册到MBean server的功能,

        5、Server,一个Server组件就代表了一个servlet容器,

        6、StandardServer,一个Server接口的标准实现,它继承了LifecycleMBeanBase,实现了Server接口,

组件初始化状态转换

        以StandardServer组件的初始化过程为例,画出如下时序图,

 tomcat组件生命周期     

        实际上StandardServer类是继承自LifecycleMBeanBase,而LifecycleMBeanBase又继承自LifecycleBase,当其他的组件在调用init()方法的时候,是调用的是StandardServer

方法的init()方法,为了能够清晰的看出调用过程和说明问题,故意将此init调用是从LifecycleBase开始。其他的组件调用StandardServer的初始化方法,开始server的初始化,在init方法中做了3件事,

        第一是调用setStateInternal()方法将StandardServer组件的状态从NEW修改为INITIALIZING,

        第二是调用StandardServer组件自身的initInternal()方法,在initInternal方法中StandardServer又做了两件事情,a、调用父类LifecycleMBeanBase的initInternal()方法,父类的该方法主要完成对StandardServer组件的注册,注册到MBen Server中,b、调用StandardServer组件中关联的其他组件的init()方法,已完成对其他组件的初始化。

        第三是再次调用setStateInternal()方法将StandardServer组件的状态修改为INITIALIZED。

        通过以上这三步完成对StandardServer组件的初始化工作。Tomcat中还有很多的组件,这些组件都直接继承了LifecycleMBeanBase类,间接继承了LifecycleBase,LifecycleBase类规定了初始化的流程,而LifecycleMBeanBase类完成了组件的注册工作,这两件事情都是固定不变的,而变化的部分,从以上时序图中第3步可以看出,这些组件只需要实现自己的initInternal()方法,在该方法中首先调用父类的initInternal()方法完成注册,其次再写自己的初始化代码,就可以完成自己的初始化工作。

        组件生命周期中的开启过程也是相似的,相比初始化的过程,少了调用父类LifecycleMBeanBase的方法。

 tomcat组件生命周期

组件事件的触发过程

 tomcat组件生命周期

        1、LifecycleBase,LifecycleBase是一个组件的父类,所有组件对于监听器注册和事件的发送都在该父类中完成。LifecycleBase负责将监听器注册到LifecycleSupport对象中。

        2、StandardContext,StandardContext是LifecycleBase的一个子类,一个StandardContext就代表着tomcat中一个webapp应用,

        3、LifecycleSupport,每一个组件对象中都会有一个对应的LifecycleSupport对象,该对象中拥有对应组件的事件监听器集合,也就是说LifecycleSupport对象知道有哪些监听器在监听组件发出的事件。

        4、LifecycleListener,监听器接口,声明了一个处理事件的接口。

        5、ContextConfig,一个监听器的具体实现,该监听器监听着StandardContext组件状态的转变,

事件监听器注册

 tomcat组件生命周期

        向StandardContext组件中添加一个ContextConfig事件监听器,可以调用StandardContext组件的addLifecycleListener()方法,

 @Override
 public void addLifecycleListener(LifecycleListener listener) {
        lifecycle.addLifecycleListener(listener);
 }<span style="color: rgb(0, 0, 192); font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>

        Lifecycle对象是StandardContext组件中一个成员变量,它的声明如下:

private LifecycleSupport lifecycle = new LifecycleSupport(this);

        向StandardContext组件中添加事件监听器,StandardContext组件会间接将该监听器通过调用LifecycleSupport 对象的addLifecycleListener方法注册到LifecycleSupport 对象,LifecycleSupport 对象拥有一个监听器集合,

private LifecycleListener listeners[] = new LifecycleListener[0];
        该集合存放着StandardContext组件所有的事件监听器。

触发事件

 tomcat组件生命周期

        在StandardContext对象的startInternal()方法中,调用fireLifecycleEvent方法,触发一个CONFIGURE_START_EVENT事件,

@Override
    protected synchronized void startInternal() throws LifecycleException {
        ......
                //ContextConfig 监听该事件,主要完成解析和web应用有关的所有web.xml配置
                fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);
     ...... 
}
    /**
     * 将该事件发送出去,由lifecycle负责发送
     * @param type  Event type
     * @param data  Data associated with event.
     */
    protected void fireLifecycleEvent(String type, Object data) {
        lifecycle.fireLifecycleEvent(type, data);
    }

        在LifecycleSupport类的fireLifecycleEvent方法中,调用每个监听器的lifecycleEvent()方法,,将该事件发送给所有的事件监听器,

/**
     * Notify all lifecycle event listeners that a particular event has
     * occurred for this Container.  The default implementation performs
     * this notification synchronously using the calling thread.
     *
     * @param type Event type
     * @param data Event data
     */
    public void fireLifecycleEvent(String type, Object data) {
 
        LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
        LifecycleListener interested[] = listeners;
        for (int i = 0; i < interested.length; i++){
        	interested[i].lifecycleEvent(event);
        }
 
    }
        在事件监听器ContextConfig接受到事件之后,在lifecycleEvent方法中,有选择地处理感兴趣的事件,

@Override
    public void lifecycleEvent(LifecycleEvent event) {
 
        // 从event事件对象中获取发送该事件的事件源
        try {
            context = (Context) event.getLifecycle();
        } catch (ClassCastException e) {
            log.error(sm.getString("contextConfig.cce", event.getLifecycle()), e);
            return;
        }
 
        // 处理感兴趣的事件
        if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
            configureStart();
        } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
            beforeStart();
        } else if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) {
            if (originalDocBase != null) {
                context.setDocBase(originalDocBase);
            }
        } else if (event.getType().equals(Lifecycle.CONFIGURE_STOP_EVENT)) {
            configureStop();
        } else if (event.getType().equals(Lifecycle.AFTER_INIT_EVENT)) {
            init();
        } else if (event.getType().equals(Lifecycle.AFTER_DESTROY_EVENT)) {
            destroy();
        }
    }