tomcat之生命周期

Catalina 由多个组件组成,当 Catalina 启动的时候,这些组件也会启动。当 Catalina 停止的时候,这些组件也必须有机会被清除。例如,当一个容器停止 工作的时候,它必须唤醒所有加载的 servlet 的 destroy 方法,而 session 管理 器要保存 session 到二级存储器中。保持组件启动和停止一致的的机制通过实现 org.apache.catalina.Lifecycle 接口来实现。

一个实现了 Lifecycle 接口的组件同是会触发一个或多个下列事件: BEFORE_START_EVENT, START_EVENT, AFTER_START_EVENT, BEFORE_STOP_EVENT, STOP_EVENT, and AFTER_STOP_EVENT。当组件被启动的时候前三个事件会被触发, 而组件停止的时候会触发后边三个事件。另外,如果一个组件可以触发事件,那 么必须存在相应的监听器来对触发的事件作出回应。监听器使用 org.apache.catalina.LifecycleListener 来表示。

Lifecycle 接口

Catalina 的设计允许一个组件包含其它的组件。例如一个容器可以包含一系列 的组件如加载器、管理器等。一个父组件负责启动和停止其子组件。Catalina 的设计成所有的组件被一个父组件来管理(in custody),所以启动 bootstrap
类只需启动一个组件即可。这种单一的启动停止机制通过继承 Lifecycle 来实现。

public interface Lifecycle {
  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 void addLifecycleListener(LifecycleListener listener);
  public LifecycleListener[] findLifecycleListeners();
  public void removeLifecycleListener(LifecycleListener listener);
  public void start() throws LifecycleException;
  public void stop() throws LifecycleException;
}

Lifecycle 中最重要的方法是 start 和 stop 方法。一个组件提供了这些方法的 实现,所以它的父组件可以通过这些方法来启动和停止他们。

另外 3 个方法 addLifecycleListener, findLifecycleListeners, 和 removeLifecycleListener 事跟监听器相关的类。组件的监听器对组件可能触发 的事件“感兴趣”,当一个事件被触发的时候,相应监听器会被通知。一个 Lifecycle 实例可以触发使用静态最终字符串定义的六个事件。

Lifecycle设计模式

现实生活中大部分的事物都有生命周期,就像人的生老病死一样。
在编程中也有很多对象是具有生命周期的,从初始化、运行、回收等 会经历几个不同的阶段。 在tomcat中容器相关的好多组建都实现了Lifecycle接口,当tomcat启动时,其依赖的下层组件会全部进行初始化。 并且可以对每个组件生命周期中的事件添加监听器。

首先是Lifecycle接口,有4中状态,分别是[启动前、启动后、关闭前、关闭后]。 并且有start()、stop()两个方法 用于启动和停止对应的对象,还有两个方法用来给该对象的生命周期事件添加监听起。

package tomcat.p5;
 
/**
 * @author zhoufeng
 */
public interface Lifecycle {
    
    public static final String BEFORE_START = "before_start";
    
    public static final String AFTER_START = "after_start";
    
    public static final String BEFORE_STOP = "before_stop";
    
    public static final String AFTER_STOP = "afater_stop";
    
    
    /**
     * 添加一个监听器
     * @param listener
     */
    void addLifecycleListener(LifecycleListener listener);
    
    /**
     * 获取所有的监听器
     * @return
     */
    LifecycleListener[] getLifecycleEvents();
    
    /**
     * 启动
     */
    void start();
    
    /**
     * 停止
     */
    void stop();
    
}

接下来看LifecycleListener接口的定义。

package tomcat.p5;
 
/**
 * 生命周期监听器接口
 * @author zhoufeng
 */
public interface LifecycleListener {
 
    /**
     * 当被监听的对象有事件发生时 会触发该方法
     * @param event
     */
    public void lifecycleEvent(LifecycleEvent event); 
    
}

下面是LifecycleEvent的定义

package tomcat.p5;
 
/**
 * 生命周期事件
 * @author zhoufeng
 */
public class LifecycleEvent {
    
    /**
     * 触发该事件的具体实例对象
     */
    private Lifecycle lifecycle ;
    
    /**
     * 事件类型(对应于Lifecycle中定义的几种状态)
     */
    private String type ;
    
    /**
     * 该事件携带的参数数据
     */
    private Object data ;
    
    
    public LifecycleEvent(Lifecycle lifecycle, String type, Object data) {
        this.lifecycle = lifecycle;
        this.type = type;
        this.data = data;
    }
 
    public Lifecycle getLifecycle() {
        return lifecycle;
    }
 
    public void setLifecycle(Lifecycle lifecycle) {
        this.lifecycle = lifecycle;
    }
 
    public String getType() {
        return type;
    }
 
    public void setType(String type) {
        this.type = type;
    }
 
    public Object getData() {
        return data;
    }
 
    public void setData(Object data) {
        this.data = data;
    }
    
    
 
}

由于很多对象类型都是具有生命周期的,如果每个需要生命周期的类都去实现一个Lifecycle接口实现里面的逻辑将会出现很多冗余代码, 有一种方式可以解决,就是写一个基类实现Lifecycle接口,然后其他类都基础该基类, 但是由于java单继承限制, 感觉用一个Lifecycle的实现类去作为一个父类不太合适,太局限了, 好比让“人类”继承“跑步”父类一样。

所以在tomcat里面用了一种设计模式,我也不太清楚这种设计模式叫什么名字, 先姑且叫它“伪继承组合”模式,使用一个LifecycleSupport类来管理一个Lifecycle的具体实例,并且有同名方法addLifecycleListener与getLifecycleListener,以及一个fireLifecycleListener方法来触发lifecycle的所有监听器。代码如下:

package tomcat.p5;
 
/**
 * @author zhoufeng
 */
public class LifecycleSupport {
    
    /**
     * 被管理的lifecycle实例
     */
    private Lifecycle lifecycle ;
    
    private LifecycleListener[] listeners ;
 
    public LifecycleSupport(Lifecycle lifecycle) {
        this.lifecycle = lifecycle;
    }
    
    public void addLifecycleListener(LifecycleListener listener){
        if(listeners == null){
            listeners = new LifecycleListener[1];
            listeners[0] = listener ;
        }else{
             LifecycleListener[] newListeners = new LifecycleListener[listeners.length + 1];
             newListeners[newListeners.length - 1] = listener ;
             listeners = newListeners ;
        }
        
    }
    
    public LifecycleListener[] getLifecycleEvents(){
        return listeners ;
    }
    
    /**
     * 触发所有的监听器
     * @param type  事件类型
     * @param data  
     */
    public void fireLifecycleEvent(String type , Object data){
        if(listeners != null && listeners.length > 0){
            for (LifecycleListener lifecycleListener : listeners) {
                lifecycleListener.lifecycleEvent(new LifecycleEvent(lifecycle, type, data));  
            }
        }
    }
 
 
}

核心的几个类都实现了。 下面来写一个例子试一试,模拟一个汽车发动到停止的过程。

首先写一个汽车发动机类,该发动机也实现了Lifecycle接口 具有生命周期。 并且使用LifecycleSupport来负责管理自己的生命周期,代码如下:

package tomcat.p5.test;
 
import tomcat.p5.Lifecycle;
import tomcat.p5.LifecycleListener;
import tomcat.p5.LifecycleSupport;
 
/**
 * 汽车发动机
 * @author zhoufeng
 */
public class Engine implements Lifecycle{
    
    private LifecycleSupport lifecycle = new LifecycleSupport(this);
    
 
    @Override
    public void addLifecycleListener(LifecycleListener listener) {
        lifecycle.addLifecycleListener(listener);
    }
 
    @Override
    public LifecycleListener[] getLifecycleEvents() {
        return lifecycle.getLifecycleEvents();
    }
 
    @Override
    public void start() {
        lifecycle.fireLifecycleEvent(Lifecycle.BEFORE_START, null);
        System.out.println("发动机启动...");
        lifecycle.fireLifecycleEvent(Lifecycle.AFTER_START, null);
    }
 
    @Override
    public void stop() {
        lifecycle.fireLifecycleEvent(Lifecycle.BEFORE_STOP, null);
        System.out.println("发动机停止...");
        lifecycle.fireLifecycleEvent(Lifecycle.AFTER_STOP, null);
    }
 
    
}

下面实现一个大灯类,代码如下,同样使用LifecycleSupport管理自己的生命周期

package tomcat.p5.test;
 
import tomcat.p5.Lifecycle;
import tomcat.p5.LifecycleListener;
import tomcat.p5.LifecycleSupport;
 
/**
 * 汽车大灯
 * @author zhoufeng
 *
 */
public class Light implements Lifecycle{
    
    private LifecycleSupport lifecycle = new LifecycleSupport(this);
    
    private String name ;
    
    public Light(String name) {
        this.name = name;
    }
 
    @Override
    public void start() {
        lifecycle.fireLifecycleEvent(Lifecycle.BEFORE_START, null); 
        System.out.println("大灯"+ this.name +"开始发光...");
        lifecycle.fireLifecycleEvent(Lifecycle.AFTER_START, null); 
    }
    
    @Override
    public void stop() {
        lifecycle.fireLifecycleEvent(Lifecycle.BEFORE_STOP, null); 
        System.out.println("大灯"+ this.name +"关闭...");
        lifecycle.fireLifecycleEvent(Lifecycle.AFTER_STOP, null); 
    }
 
    @Override
    public void addLifecycleListener(LifecycleListener listener) {
        lifecycle.addLifecycleListener(listener); 
    }
 
    @Override
    public LifecycleListener[] getLifecycleEvents() {
        return lifecycle.getLifecycleEvents();
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
    
    
}

接下来就是汽车类了,里面包含了一个Engine,两个Light,注意看start()和stop()两个方法,当汽车启动时,会先将它依赖的一些组件全部启动。 停止时也一样,现将依赖的其他组件一起停止。

package tomcat.p5.test;
 
import tomcat.p5.Lifecycle;
import tomcat.p5.LifecycleListener;
import tomcat.p5.LifecycleSupport;
 
/**
 * 汽车
 * @author zhoufeng
 */
public class Car implements Lifecycle{
 
    private Light leftLight ; //左大灯
    private Light rightLight ; //右大灯
 
    private Engine engine ; //引擎
 
    private LifecycleSupport lifecycle = new LifecycleSupport(this);
 
    public void run(){
        start();
        System.out.println("桑塔拉跑起来了...");
    }
 
    public void shutdown(){
        stop();
        System.out.println("桑塔拉停止了...");
    }
 
    @Override
    public void addLifecycleListener(LifecycleListener listener) {
        lifecycle.addLifecycleListener(listener);
    }
 
    @Override
    public LifecycleListener[] getLifecycleEvents() {
        return lifecycle.getLifecycleEvents();
    }
 
    @Override
    public void start() {
        lifecycle.fireLifecycleEvent(Lifecycle.BEFORE_START, null);
        //先初始化其他组件
        if(engine != null && engine instanceof Lifecycle){
            ((Lifecycle)engine).start();
        }
        if(leftLight != null && leftLight instanceof Lifecycle){
            ((Lifecycle)leftLight).start();
        }
        if(rightLight != null && rightLight instanceof Lifecycle){
            ((Lifecycle)rightLight).start();
        }
 
        System.out.println("桑塔拉正在启动...");
        lifecycle.fireLifecycleEvent(Lifecycle.AFTER_START, null);
    }
 
    @Override
    public void stop() {
        //先停止其他组件
        if(engine != null && engine instanceof Lifecycle){
            ((Lifecycle)engine).stop(); 
        }
        if(leftLight != null && leftLight instanceof Lifecycle){
            ((Lifecycle)leftLight).stop();
        }
        if(rightLight != null && rightLight instanceof Lifecycle){
            ((Lifecycle)rightLight).stop();
        }
 
        lifecycle.fireLifecycleEvent(Lifecycle.BEFORE_STOP, null);
        System.out.println("桑塔拉正在停止...");
        lifecycle.fireLifecycleEvent(Lifecycle.AFTER_STOP, null);
    }
 
    public Light getLeftLight() {
        return leftLight;
    }
 
    public void setLeftLight(Light leftLight) {
        this.leftLight = leftLight;
    }
 
    public Light getRightLight() {
        return rightLight;
    }
 
    public void setRightLight(Light rightLight) {
        this.rightLight = rightLight;
    }
 
    public Engine getEngine() {
        return engine;
    }
 
    public void setEngine(Engine engine) {
        this.engine = engine;
    }
 
}

下面写一个入口程序来测试一下。

package tomcat.p5.test;
 
import tomcat.p5.Lifecycle;
import tomcat.p5.LifecycleEvent;
import tomcat.p5.LifecycleListener;
 
public class Startup {
    
    public static void main(String[] args) throws InterruptedException {
        
        //实例化两个灯泡
        Light leftLight = new Light(" 左 ");
        Light rightLight = new Light(" 右 ");
        
        //实例化一个发动机
        Engine engine = new Engine();
        
        //实例化一个汽车
        Car car = new Car() ;
        car.setLeftLight(leftLight);
        car.setRightLight(rightLight);
        car.setEngine(engine);
        
    
        //还可以给上面实现了Lifecycle接口的组件添加监听器
        engine.addLifecycleListener(new LifecycleListener() {
            @Override
            public void lifecycleEvent(LifecycleEvent event) {
                //只关心AFTER_START事件
                if(Lifecycle.AFTER_START.equals(event.getType())){
                    System.out.println("监听到发动机启动了,轰轰轰。。。");
                    //这里还可以通过event.getLifecycle()获得engin实例对象,然后做一些业务操作
                }else{
                    //这里可以继续判断其他类型的事件,然后做出处理
                }
            }
        });
        
        car.addLifecycleListener(new LifecycleListener() {
            @Override
            public void lifecycleEvent(LifecycleEvent event) { 
                if(Lifecycle.AFTER_STOP.equals(event.getType())){
                    System.out.println("桑塔拉快停止了,下车吧。。。");
                }
            }
        });
        
        //启动汽车
        car.run();
        
        System.out.println("\n\n\n");
        
        //模拟让桑塔拉跑3秒
        Thread.sleep(3000);
        
        //关闭汽车
        car.shutdown();
        
    }
 
}

输出如下

发动机启动...
监听到发动机启动了,轰轰轰。。。
大灯 左 开始发光...
大灯 右 开始发光...
桑塔拉正在启动...
桑塔拉跑起来了...




发动机停止...
大灯 左 关闭...
大灯 右 关闭...
桑塔拉正在停止...
桑塔拉停止了,下车吧。。。
桑塔拉停止了...
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355