专栏名称: 预流
敲代码的
目录
相关文章推荐
51好读  ›  专栏  ›  预流

Tomcat 7 启动分析(五)Lifecycle 机制和实现原理

预流  · 掘金  ·  · 2018-01-31 06:19

正文

上篇文章分析 Tomcat 7 的各组件的 init、start 方法 时经常会看到有一个 setStateInternal 方法的调用,在查看 LifecycleBase 类及其它各组件的源码时会在多处看到这个方法的调用,这篇文章就来说说这方法,以及与这个方法相关的 Tomcat 的 Lifecycle 机制和实现原理。

接上文里谈到了 Tomcat 7 的各组件的父类 LifecycleBase 类,该类实现了接口 org.apache.catalina.Lifecycle,下面是这个接口里定义的常量和方法:

细心的读者会发现,上篇文章里提到的 init 和 start 方法实际上是在这个接口里面定义好的,也正因为有各组件最终都会实现这个接口作为前提条件,所以才能支持组件内部的 initInternal、startInternal 方法内对于子组件(组件里面嵌套的子组件都是以接口的形式定义的,但这些接口都会以 Lifecycle 作为父接口)的 init 和 start 方法的调用。通过这种方式,只要调用了最外层的 Server 组件的 init 和 start 方法,就可以将 Tomcat 内部的各级子组件初始化和启动起来。我叫这种方式为链式调用。实际上关于 Tomcat 的关闭机制也是通过这种方式一步步调用各层组件的 stop 方法的。这里不再展开叙述,留待读者自己研究研究吧。

Lifecycle 接口中的这些字符串常量定义主要用于事件类型的定义,先按下不表,文章后面会提到。

重点看下面三个方法:


    /**
     * 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. 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);//删除该组件中的一个监听器

这三个方法的作用在代码的注释里简要说明了一下。这三个方法涉及 org.apache.catalina.LifecycleListener 接口,那么就看下这个接口的定义:


public interface LifecycleListener {


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


}

如此简单,只有一个方法,这个方法用作某个事件( org.apache.catalina.LifecycleEvent )产生时通知当前监听器的实现类,具体针对该事件如何处理由监听器实现类自己决定。

看下 LifecycleEvent 的实现:


public final class LifecycleEvent extends EventObject {

    private static final long serialVersionUID = 1L;


    // ----------------------------------------------------------- Constructors

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


    // ----------------------------------------------------- Instance Variables


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


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


    // ------------------------------------------------------------- Properties


    /**
     * Return the event data of this event.
     */
    public Object getData() {

        return (this.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);

    }


}

这个类也很简单,data 和 type 作为类的内置实例变量,唯一特别是使用了 jdk 内置的 java.util.EventObject 作为父类来支持事件定义,这里在事件构造函数中将 org.apache.catalina.Lifecycle 类的实例 lifecycle 作为事件源,保存 lifecycle 对象的引用,并提供了 getLifecycle 方法返回这个引用。

那么 Tomcat 中是如何实现关于这些事件的监听以及通知的呢?

在本文开头提到 的LifecycleBase 类中第 47 行定义了一个实例变量 lifecycle ,正是通过该变量来注册组件上定义的各类监听器的。留心一下 lifecycle 这个实例变量,它并不是 org.apache.catalina.Lifecycle 类的实例,而是 org.apache.catalina.util.LifecycleSupport 类的实例。正是这个工具类提供了事件监听和事件通知的功能。

先看下实际代码中是如何给组件发布时间通知的,看下前面文章中曾经提到过的 org.apache.catalina.core.StandardServer 类的 startInternal 方法:


     1	    protected void startInternal() throws LifecycleException {
     2	
     3	        fireLifecycleEvent(CONFIGURE_START_EVENT, null);
     4	        setState(LifecycleState.STARTING);
     5	
     6	        globalNamingResources.start();
     7	        
     8	        // Start our defined Services
     9	        synchronized (services) {
    10	            for (int i = 0; i < services.length; i++) {
    11	                services[i].start();
    12	            }
    13	        }
    14	    }

我们前面已经分析过第 9 到 13 行代码,这里看下第 3 行,它调用了父类 org.apache.catalina.util.LifecycleBase 里的 fireLifecycleEvent 方法,这里的 CONFIGURE_START_EVENT 就是本文最开始 Lifecycle 接口中定义的常量,这里表示发布了一个 start 配置事件。

org.apache.catalina.util.LifecycleBase 类中的 fireLifecycleEvent 方法里调用的是 org.apache.catalina.util.LifecycleSupport 类 fireLifecycleEvent 方法,该方法代码如下:


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

    }

通过传进来的两个参数构造一个 LifecycleEvent 对象,然后向注册到组件中的所有监听器发布这个新构造的事件对象。

这里有个疑问,到底什么时候向组件里注册监听器的呢?

还是以 StandardServer 举例,在前面讲 Digester 的使用时,org.apache.catalina.startup.Catalina 类的 createStartDigester 方法有这么一段代码:


     1	        // Configure the actions we will be using
     2	        digester.addObjectCreate("Server",
     3	                                 "org.apache.catalina.core.StandardServer",
     4	                                 "className");
     5	        digester.addSetProperties("Server");
     6	        digester.addSetNext("Server",
     7	                            "setServer",
     8	                            "org.apache.catalina.Server");
     9	
    10	        digester.addObjectCreate("Server/GlobalNamingResources",
    11	                                 "org.apache.catalina.deploy.NamingResources");
    12	        digester.addSetProperties("Server/GlobalNamingResources");
    13	        digester.addSetNext("Server/GlobalNamingResources",
    14	                            "setGlobalNamingResources",
    15	                            "org.apache.catalina.deploy.NamingResources");
    16	
    17	        digester.addObjectCreate("Server/Listener",
    18	                                 null, // MUST be specified in the element
    19	                                 "className");
    20	        digester.addSetProperties("Server/Listener");
    21	        digester.addSetNext("Server/Listener",
    22	                            "addLifecycleListener",
    23	                            "org.apache.catalina.LifecycleListener");

第 17 到 24 行,将调用 org.apache.catalina.core.StandardServer 类的 addLifecycleListener 方法,将根据 server.xml 中配置的 Server 节点下的 Listener 节点所定义的 className 属性构造对象实例,并作为 addLifecycleListener 方法的入参。所有的监听器都会实现上面提到的 org.apache.catalina.LifecycleListener 接口。Server 节点下的 Listener 节点有好几个,这里以 org.apache.catalina.core.JasperListener 举例。

在构造完 org.apache.catalina.core.JasperListener 类的对象之后,调用 addLifecycleListener 方法,这个方法并没有直接在 org.apache.catalina.core.StandardServer 类中定义,而是在它的父类 org.apache.catalina.util.LifecycleBase 中:


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

这里调用的是前述的 org.apache.catalina.util.LifecycleSupport 类的 addLifecycleListener 方法:


    /**
     * Add a lifecycle event listener to this component.
     *
     * @param listener The listener to add
     */
    public void addLifecycleListener(LifecycleListener listener) {

      synchronized (listenersLock) {
          LifecycleListener results[] =
            new LifecycleListener[listeners.length + 1];
          for (int i = 0; i < listeners.length; i++)
              results[i] = listeners[i];
          results[listeners.length] = listener;
          listeners = results;
      }

    }

LifecycleSupport 作为一个工具类,内部保存了一个监听器对象实例数组,见该类的第 68 行:







请到「今天看啥」查看全文