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

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

  • 观察者模式


    Tomcat生命周期管理与观察者模式_第1张图片
    图片.png

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

    • 订阅者订阅


      Tomcat生命周期管理与观察者模式_第2张图片
      图片.png
    • 发布者发布

      Tomcat生命周期管理与观察者模式_第3张图片
      图片.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 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:
     * 
    *
  1. INIT_EVENT: On the successful completion of component * initialization.
  2. *
* * @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: *
    *
  1. BEFORE_START_EVENT: At the beginning of the method. It is as this * point the state transitions to * {@link LifecycleState#STARTING_PREP}.
  2. *
  3. 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.
  4. *
  5. 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}. *
  6. *
* * @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: *
    *
  1. BEFORE_STOP_EVENT: At the beginning of the method. It is at this * point that the state transitions to * {@link LifecycleState#STOPPING_PREP}.
  2. *
  3. 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.
  4. *
  5. 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}. *
  6. *
* * 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: *
    *
  1. DESTROY_EVENT: On the successful completion of component * destruction.
  2. *
* * @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启动完毕。

你可能感兴趣的:(Tomcat生命周期管理与观察者模式)