Tomcat生命周期管理与观察者模式

请结合Servlet工作原理阅读
在这之前,我简单的讲述一下观察者模式:
观察者模式又叫做发布-订阅(Publish/Subscribe)模式、源-监听(Source/Listener)模式。它定义了一种一对多的依赖关系,一个主题,多个观察者,当主题发生变化的时候,会主动的通知观察者,这样观察者便能针对主题发生的变化,执行某些对应的动作。观察者模式的应用非常广泛,如Java AWT事件模型,Servlet的监听器,Spring事件处理机制以及本文所讲述的Tomcat生命周期管理机制等等。

  • 观察者模式


    图片.png

    实现该模式,通常需要两个过程:

    • 订阅者订阅


      图片.png
    • 发布者发布

      图片.png

      下面我给出一个具体示例:
      抽象主题

package com.liyaocai;


/**
 * 抽象主题 .
 *
 * @author liyaocai
 * @version V1.0
 * @date 2018/8/17 15:31
 * @since 1.8
 */
public interface Observable {
  /**
   * 添加观察者
   * @author liyaocai
   * @param observer
   * @return
   * @throws
   */
  void addObsrver(Observer observer);

  /**
   * 删除观察者
   * @author liyaocai
   * @param observer
   * @return
   * @throws
   */
  void deletebserver(Observer observer);

  /**
   * 事件发生,通知观察者
   * @author liyaocai
   */
  void notifybservsers();
}

抽象观察者

package com.liyaocai;

/**
 * 抽象观察者 .
 *
 * @author liyaocai
 * @version V1.0
 * @date 2018/8/17 15:41
 * @since 1.8
 */
public interface Observer {

  /**
   * 更新方法,观察者根据传入的主题对象获取主题的上下文
   *
   * 根据传入的Object对象判断发生了何种事件
   */

  void update(Observable observable, Object arg);
}

具体主题

package com.liyaocai;

import java.util.ArrayList;
import java.util.List;

/**
 * 模拟Tomcat容器 .
 *
 * @author liyaocai
 * @version V1.0
 * @date 2018/8/17 15:36
 * @since 1.8
 */

public class Container implements Observable {

  /**
   * 观察者列表
   */
  private List<Observer> observers = new ArrayList<>();

  @Override
  public void addObsrver(Observer observer) {
    observers.add(observer);
  }

  @Override
  public void deletebserver(Observer observer) {
    observers.remove(observer);
  }

  @Override
  public void notifybservsers() {
    for (Observer observer : observers) {
      observer.update(this, "container start");
    }
  }

  /**
   * 容器启动方法,并且通知观察者
   * @author liyaocai
   * @param
   * @return
   * @throws
   */
  public void start(){
    System.out.println("container start");
    notifybservsers();
  }
}

具体观察者

package com.liyaocai;

/**
 * 具体观察者,模拟容器监听类 .
 *
 * @author liyaocai
 * @version V1.0
 * @date 2018/8/17 15:44
 * @since 1.8
 */

public class ContainerConfig implements Observer {

  @Override
  public void update(Observable observable, Object arg) {
    String event = (String) arg;
    if (event.equals("container start"))
    {
      System.out.println("container starting");
    //   do container configs
    }

  }
}

实际上,监听器模式也是如此,观察者(Observer)相当于事件监听者,被观察者(Observable)相当于事件源和事件,事件源经过事件的封装传给监听器,当事件源触发事件后,监听器接收到事件对象可以回调事件的方法。

Tomcat的生命周期管理

在了解了观察者模式之后,我们正式开始了解Tomcat的生命周期管理,在Tomcat的源码中,下面是相关的类:

  • Lifecycle:相当于抽象主题角色,所有的容器类与组件实现类都实现了这个接口。如StandardContext
  • LifecycleListener:相当于抽象观察者角色,具体的实现类有ContextConfig, HostConfig, EngineConfig类,它们在容器启动时与停止时触发。
  • LifecycleEvent:生命周期事件,对主题与发生的事件进行封装。
  • LifecycleSupport:生命周期管理的实用类,提供对观察者的添加,删除及通知观察者的方法。(Tomcat8.5中已经移除,使用CopyOnWriteArrayList来管理监听者集合)
  • LifecycleException:生命周期异常
Lifecycle接口

Lifecycle相当于观察者模式中的抽象主题角色(Observable),它定义了添加、删除及通知管理者的方法。并且定义了13个与生命周期相关的事件,Start和stop方法是Lifecycle最重要的两个方法,分别代表启动与停止。所有四种容器的标准实现类(StandardEngine, StandardHost, StandardContext,StandardWrapper)和基本组件(Logger,Loader,Manager等)的实现类都实现了Lifecycle接口。容器启动时,主要做三件事:调用组件的启动方法,启动组件;调用子容器的启动方法,启动子容器;通知容器的观察者,使其执行相应的启动动作。子容器启动也做这三件事,这样整个Tomcat便启动了。

public interface Lifecycle {


    // ----------------------------------------------------- Manifest Constants


    /**
     * The LifecycleEvent type for the "component before init" event.
     */
    public static final String BEFORE_INIT_EVENT = "before_init";


    /**
     * The LifecycleEvent type for the "component after init" event.
     */
    public static final String AFTER_INIT_EVENT = "after_init";


    /**
     * The LifecycleEvent type for the "component start" event.
     */
    public static final String START_EVENT = "start";


    /**
     * The LifecycleEvent type for the "component before start" event.
     */
    public static final String BEFORE_START_EVENT = "before_start";


    /**
     * The LifecycleEvent type for the "component after start" event.
     */
    public static final String AFTER_START_EVENT = "after_start";


    /**
     * The LifecycleEvent type for the "component stop" event.
     */
    public static final String STOP_EVENT = "stop";


    /**
     * The LifecycleEvent type for the "component before stop" event.
     */
    public static final String BEFORE_STOP_EVENT = "before_stop";


    /**
     * The LifecycleEvent type for the "component after stop" event.
     */
    public static final String AFTER_STOP_EVENT = "after_stop";


    /**
     * The LifecycleEvent type for the "component after destroy" event.
     */
    public static final String AFTER_DESTROY_EVENT = "after_destroy";


    /**
     * The LifecycleEvent type for the "component before destroy" event.
     */
    public static final String BEFORE_DESTROY_EVENT = "before_destroy";


    /**
     * The LifecycleEvent type for the "periodic" event.
     */
    public static final String PERIODIC_EVENT = "periodic";


    /**
     * The LifecycleEvent type for the "configure_start" event. Used by those
     * components that use a separate component to perform configuration and
     * need to signal when configuration should be performed - usually after
     * {@link #BEFORE_START_EVENT} and before {@link #START_EVENT}.
     */
    public static final String CONFIGURE_START_EVENT = "configure_start";


    /**
     * The LifecycleEvent type for the "configure_stop" event. Used by those
     * components that use a separate component to perform configuration and
     * need to signal when de-configuration should be performed - usually after
     * {@link #STOP_EVENT} and before {@link #AFTER_STOP_EVENT}.
     */
    public static final String CONFIGURE_STOP_EVENT = "configure_stop";


    // --------------------------------------------------------- Public Methods


    /**
     * Add a LifecycleEvent listener to this component.
     *
     * @param listener The listener to add
     */
    public void addLifecycleListener(LifecycleListener listener);


    /**
     * Get the life cycle listeners associated with this life cycle.
     *
     * @return An array containing the life cycle listeners associated with this
     *         life cycle. If this component has no listeners registered, a
     *         zero-length array is returned.
     */
    public LifecycleListener[] findLifecycleListeners();


    /**
     * Remove a LifecycleEvent listener from this component.
     *
     * @param listener The listener to remove
     */
    public void removeLifecycleListener(LifecycleListener listener);


    /**
     * Prepare the component for starting. This method should perform any
     * initialization required post object creation. The following
     * {@link LifecycleEvent}s will be fired in the following order:
     * <ol>
     *   <li>INIT_EVENT: On the successful completion of component
     *                   initialization.</li>
     * </ol>
     *
     * @exception LifecycleException if this component detects a fatal error
     *  that prevents this component from being used
     */
    public void init() throws LifecycleException;

    /**
     * Prepare for the beginning of active use of the public methods other than
     * property getters/setters and life cycle methods of this component. This
     * method should be called before any of the public methods other than
     * property getters/setters and life cycle methods of this component are
     * utilized. The following {@link LifecycleEvent}s will be fired in the
     * following order:
     * <ol>
     *   <li>BEFORE_START_EVENT: At the beginning of the method. It is as this
     *                           point the state transitions to
     *                           {@link LifecycleState#STARTING_PREP}.</li>
     *   <li>START_EVENT: During the method once it is safe to call start() for
     *                    any child components. It is at this point that the
     *                    state transitions to {@link LifecycleState#STARTING}
     *                    and that the public methods other than property
     *                    getters/setters and life cycle methods may be
     *                    used.</li>
     *   <li>AFTER_START_EVENT: At the end of the method, immediately before it
     *                          returns. It is at this point that the state
     *                          transitions to {@link LifecycleState#STARTED}.
     *                          </li>
     * </ol>
     *
     * @exception LifecycleException if this component detects a fatal error
     *  that prevents this component from being used
     */
    public void start() throws LifecycleException;


    /**
     * Gracefully terminate the active use of the public methods other than
     * property getters/setters and life cycle methods of this component. Once
     * the STOP_EVENT is fired, the public methods other than property
     * getters/setters and life cycle methods should not be used. The following
     * {@link LifecycleEvent}s will be fired in the following order:
     * <ol>
     *   <li>BEFORE_STOP_EVENT: At the beginning of the method. It is at this
     *                          point that the state transitions to
     *                          {@link LifecycleState#STOPPING_PREP}.</li>
     *   <li>STOP_EVENT: During the method once it is safe to call stop() for
     *                   any child components. It is at this point that the
     *                   state transitions to {@link LifecycleState#STOPPING}
     *                   and that the public methods other than property
     *                   getters/setters and life cycle methods may no longer be
     *                   used.</li>
     *   <li>AFTER_STOP_EVENT: At the end of the method, immediately before it
     *                         returns. It is at this point that the state
     *                         transitions to {@link LifecycleState#STOPPED}.
     *                         </li>
     * </ol>
     *
     * Note that if transitioning from {@link LifecycleState#FAILED} then the
     * three events above will be fired but the component will transition
     * directly from {@link LifecycleState#FAILED} to
     * {@link LifecycleState#STOPPING}, bypassing
     * {@link LifecycleState#STOPPING_PREP}
     *
     * @exception LifecycleException if this component detects a fatal error
     *  that needs to be reported
     */
    public void stop() throws LifecycleException;

    /**
     * Prepare to discard the object. The following {@link LifecycleEvent}s will
     * be fired in the following order:
     * <ol>
     *   <li>DESTROY_EVENT: On the successful completion of component
     *                      destruction.</li>
     * </ol>
     *
     * @exception LifecycleException if this component detects a fatal error
     *  that prevents this component from being used
     */
    public void destroy() throws LifecycleException;


    /**
     * Obtain the current state of the source component.
     *
     * @return The current state of the source component.
     */
    public LifecycleState getState();


    /**
     * Obtain a textual representation of the current component state. Useful
     * for JMX. The format of this string may vary between point releases and
     * should not be relied upon to determine component state. To determine
     * component state, use {@link #getState()}.
     *
     * @return The name of the current component state.
     */
    public String getStateName();


    /**
     * Marker interface used to indicate that the instance should only be used
     * once. Calling {@link #stop()} on an instance that supports this interface
     * will automatically call {@link #destroy()} after {@link #stop()}
     * completes.
     */
    public interface SingleUse {
    }
}

我们来看一下具体的启动过程,

@Override
public final synchronized void start() throws LifecycleException {
    //判断容器是否已经在启动或者已经启动
    if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) ||
    LifecycleState.STARTED.equals(state)) {

    if (log.isDebugEnabled()) {
    Exception e = new LifecycleException();
    log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e);
    } else if (log.isInfoEnabled()) {
    log.info(sm.getString("lifecycleBase.alreadyStarted", toString()));
    }

    return;
    }
    //容器未启动
    if (state.equals(LifecycleState.NEW)) {
    //  初始化容器,更改生命状态,通知容器观察者(由具体容器实现)
    init();
    } else if (state.equals(LifecycleState.FAILED)) {
    //  初始化失败,则停止
    stop();
    } else if (!state.equals(LifecycleState.INITIALIZED) &&
    !state.equals(LifecycleState.STOPPED)) {
    invalidTransition(Lifecycle.BEFORE_START_EVENT);
    }

    try {
    //  设置生命状态
    setStateInternal(LifecycleState.STARTING_PREP, null, false);
    //启动容器,调用子容器的启动方法,启动子容器,通知容器观察者(由具体容器实现)
    startInternal();
    if (state.equals(LifecycleState.FAILED)) {
    // This is a 'controlled' failure. The component put itself into the
    // FAILED state so call stop() to complete the clean-up.
    stop();
    } else if (!state.equals(LifecycleState.STARTING)) {
    // Shouldn't be necessary but acts as a check that sub-classes are
    // doing what they are supposed to.
    invalidTransition(Lifecycle.AFTER_START_EVENT);
    } else {
    setStateInternal(LifecycleState.STARTED, null, false);
    }
    } catch (Throwable t) {
    // This is an 'uncontrolled' failure so put the component into the
    // FAILED state and throw an exception.
    ExceptionUtils.handleThrowable(t);
    setStateInternal(LifecycleState.FAILED, null, false);
    throw new LifecycleException(sm.getString("lifecycleBase.startFail", toString()), t);
    }
    }

LifecycleListener接口
public interface LifecycleListener {


    /**
     * Acknowledge the occurrence of the specified event.
     *
     * @param event LifecycleEvent that has occurred
     */
    public void lifecycleEvent(LifecycleEvent event);


}

LifecycleListener接口提供了一个更新方法,监听器通过事件类型来做出响应操作,与上面的示例代码的观察者模式相比(一种变形),Event封装了事件源(也就是具体主题与事件的类型)。

LifecycleEvent

我们来看一下是如何封装的,

public final class LifecycleEvent extends EventObject {

    private static final long serialVersionUID = 1L;


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


    /**
     * The event data associated with this event.
     */
    private final Object data;


    /**
     * The event type this instance represents.
     */
    private final String type;


    /**
     * @return the event data of this event.
     */
    public Object getData() {
        return data;
    }


    /**
     * @return the Lifecycle on which this event occurred.
     */
    public Lifecycle getLifecycle() {
        return (Lifecycle) getSource();
    }


    /**
     * @return the event type of this event.
     */
    public String getType() {
        return this.type;
    }
}

可以看出,事件封装了事件源(具体的主题)、事件的类型以及需要事件的数据。
最后总结一下:tomcat的启动过程:调用组件的启动方法,启动组件;调用子容器的启动方法,启动子容器;通知容器的观察者,使其执行相应的启动动作。每一层次的容器都这样启动,最终整个Tomcat启动完毕。

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