在上一篇文章中:Tomcat服务器顶层结构和启动过程 对Tomcat的整体架构有了一个大致的了解,这一篇主要是学习一下Tomcat的整个生命周期的管理。

Tomcat的生命周期管理使用了观察者模式,使Tomcat的生命周期管理机制设计的非常优雅,在Tomcat启动时,只需要启动一个Server组件,就会启动所有的容器及对应的组件,并且触发这些容器的监听者,完成启动过程的设置。可以说是“一键式”启动的。停止过程也是一样。

一、观察者模式简单描述

(1)观察者模式有时被称作:发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

观察者模式的应用非常广泛,如Java AWT事件模型,Servlet的监听器,Spring事件处理机制以及Tomcat生命周期管理机制等等。

(2)观察者模式解决的问题

将一个系统分割成一个一些类相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。观察者就是解决这类的耦合关系的。

(3)观察者模式中有3类角色对象:

1、抽象主题(Subject):它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。

2、具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。

3、抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。

4、具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。
  
(4)观察者模式的类图:

这里写图片描述

二、Tomcat的生命周期管理相关类

关于Tomcat的生命周期管理所涉及的相关类主要有:

(1)Lifecycle:相当于抽象主题角色,所有的容器类与组件实现类都实现了这个接口。如StandardContext

(2)LifecycleListener:相当于抽象观察者角色,具体的实现类有ContextConfig, HostConfig, EngineConfig类,它们在容器启动时与停止时触发。

(3)LifecycleEvent:生命周期事件,对主题与发生的事件进行封装。

(4)LifecycleSupport:生命周期管理的实用类,提供对观察者的添加,删除及通知观察者的方法。(Tomcat release 9.0.x版本中没有用到这个)

(5)LifecycleException:生命周期异常类。

三、Lifecycle接口介绍

组件生命周期方法的通用接口。org.apache.catalina.Lifecycle Tomcat通过Lifecycle接口统一管理生命周期,所有有生命周期的组件都要实现Lifecycle接口,以便提供一致的机制去启动和停止组件。Lifecycle接口内容如下:

这里写图片描述

上图中可以看出Lifecycle接口一共做了四件事情:

(1)定义了13个String类型常量:这些常量信息用于LifecycleEvent事件的type属性中,作用是区分组件发出的LifecycleEvent事件是的状态(如初始化前、启动前、启动中等)。这种设计方法可以让多种状态都发送同一种类型的时间,然后用其中的一个属性类区分状态而不用定义多种事件。

(2)定义了3个管理监听器的方法:addLifecycleListener、findLifecycleListeners和removeLifecycleListener。分别用来添加、查找和删除LifecycleListener类型的监听器。源码如下图所示:

这里写图片描述

(3)定义了4个生命周期的方法:init、start、stop和destory,用于执行生命周期的各个阶段,接口定义如下:

public void init() throws LifecycleException;

public void start() throws LifecycleException;

public void stop() throws LifecycleException;

public void destroy() throws LifecycleException;

(4)定义了获取当前和状态的两个方法: getState和getStateName,用来获取当前的状态,getState的返回值LifecycleState是枚举类型,里边列举了生命周期的各个节点,getStateName方法返回String类型的状态的名字。

完整的Lifecycle 接口定义代码如下:


package org.apache.catalina;

public interface Lifecycle {

    public static final String BEFORE_INIT_EVENT = "before_init";
    public static final String AFTER_INIT_EVENT = "after_init";
    public static final String START_EVENT = "start";
    public static final String BEFORE_START_EVENT = "before_start";
    public static final String AFTER_START_EVENT = "after_start";
    public static final String STOP_EVENT = "stop";
    public static final String BEFORE_STOP_EVENT = "before_stop";
    public static final String AFTER_STOP_EVENT = "after_stop";
    public static final String AFTER_DESTROY_EVENT = "after_destroy";
    public static final String BEFORE_DESTROY_EVENT = "before_destroy";
    public static final String PERIODIC_EVENT = "periodic";
    public static final String CONFIGURE_START_EVENT = "configure_start";
    public static final String CONFIGURE_STOP_EVENT = "configure_stop";

    public void addLifecycleListener(LifecycleListener listener);
    public LifecycleListener[] findLifecycleListeners();
    public void removeLifecycleListener(LifecycleListener listener);
    public void init() throws LifecycleException;
    public void start() throws LifecycleException;
    public void stop() throws LifecycleException;
    public void destroy() throws LifecycleException;
    public LifecycleState getState();
    public String getStateName();
    public interface SingleUse {
    }
}

四、Lifecycle接口默认实现LifecycleBase

Lifecycle接口的默认实现是org.apache.catalina.util.LifecycleBase ,在LifecycleBase实现类中实现了Lifecycle接口中定义的方法,类结构图如下:

这里写图片描述

(1)3个管理监听器的方法

    private final List<LifecycleListener> lifecycleListeners = new CopyOnWriteArrayList<>();

    @Override
    public void addLifecycleListener(LifecycleListener listener) {
        lifecycleListeners.add(listener);
    }

    @Override
    public LifecycleListener[] findLifecycleListeners() {
        return lifecycleListeners.toArray(new LifecycleListener[0]);
    }

    @Override
    public void removeLifecycleListener(LifecycleListener listener) {
        lifecycleListeners.remove(listener);
    }

可以看出LifecycleBase定义了一个lifecycleListeners 集合用于保存所有的监听器,然后并定义了添加、删除、查找和执行监听器的方法;

(2)4个生命周期的方法:init、start、stop和destory

    protected abstract void initInternal() throws LifecycleException;

    @Override
    public final synchronized void init() throws LifecycleException {
        //开始的状态必须是LifecycleState.NEW,否则会抛出异常
        if (!state.equals(LifecycleState.NEW)) {
            invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
        }

        try {
            //在初始化之前,将状态设置为LifecycleState.INITIALIZING 表示正在初始化中
            setStateInternal(LifecycleState.INITIALIZING, null, false);
            //使用模板的方式进行具体的初始化,该抽象方法是由子类实现的
            initInternal();
            //在初始化之后,将状态设置为LifecycleState.INITIALIZED 表示初始化完成
            setStateInternal(LifecycleState.INITIALIZED, null, false);
        } catch (Throwable t) {
            handleSubClassException(t, "lifecycleBase.initFail", toString());
        }
    }

这里对四个生命周期,只讨论init方法,其他三种大致相同。

在init方法中调用了所对应的模板方法initInternal() 该方法并没有具体的实现,而是让子类去具体的实现,因此对于子类来说,执行生命周期的方法就是:initInternal、startInternal、stopInternal、destroyInternal;

(3)定义了获取当前和状态的两个方法:getState和getStateName

    private volatile LifecycleState state = LifecycleState.NEW;

    @Override
    public LifecycleState getState() {
        return state;
    }

    @Override
    public LifecycleState getState() {
        return state;
    }

    @Override
    public String getStateName() {
        return getState().toString();
    }

在生命周期相应的方法中已经设置了state的属性,所以通过这两个方法就可以简单的实现获取state。

五、再谈Tomcat中的观察者模式

Tomcat中的观察者模式:

这里写图片描述

Tomcat中Lifecycle就是抽象的主题。

然后像StandardEngine、StandardHost、StandardContext、StandardServer这类Container对象,都是具体主题。

LifecycleListener定义了观察者想要执行的方法。就是前面提到的,如果观察者对主题的某个动作感兴趣,他就会做自己的动作,这个动作就是LifecycleListener里的方法。当然LifecycleListener是一个接口,用户可以定义各种具体的观察者。

Tomcat对观察者模式做了很好的扩展,他增加了一个LifecycleSupport来代替主题管理多个观察者,把功能模块分得更清晰,LifecycleSupport中定义了一个LifecycleListener的数组。主题中某动作发生时,LifecycleSupport会遍历此数组,对每一个listener调用它们像要做的方法。

下面的方法就是LifecycleSupport通知各个LifecycleListener某事件发生了。

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

    }

Tomcat中将事件定义为LifecycleEvent

    /**
     * Construct a new LifecycleEvent with the specified parameters.
     *
     * @param lifecycle Component on which this event occurred
     * @param type Event type (required)
     * @param data Event data (if any)
     */
    public LifecycleEvent(Lifecycle lifecycle, String type, Object data) {
        super(lifecycle);
        this.type = type;
        this.data = data;
    }

事件有一个属性type,用来标明事件的类型。

也就是说Tomcat中观察者模式流程:
1、将观察者listener增加到LifecycleSupport的listener数组中
2、当container(主题)做某些动作的时候,会生成一个LifecycleEvent对象,这个对象标明当前这个动作是一个什么事件,然后LifecycleSupport会通知listener数组中的每一个观察者该事件的发生。
3、listener会根据LifecycleEvent判断事件的类型,完成相应的动作。


参考文章:

1、https://my.oschina.net/u/227422/blog/66213
2、http://www.cnblogs.com/chenying99/archive/2012/09/05/2671199.html

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐