zoukankan      html  css  js  c++  java
  • Tomcat中组件的生命周期管理(二)

    本文主要是源码分析了Catalina中生命周期管理中两个核心类LifecycleSupportLifecycleBase

    在上一篇文章中,我们将Catalina中生命周期的相关类都进行了大致的讲解,从中我们可以看出生命周期功能中最重要的两个类分别是LifecycleSupportLifecycleBase,今天这篇文章就主要对这两个类的源码进行分析从而理解其实现原理。

    LifecycleSupport源码分析

    /**
     * Support class to assist in firing LifecycleEvent notifications to
     * registered LifecycleListeners.
     *
     * @author Craig R. McClanahan
     */
    public final class LifecycleSupport {
    
    
    // ----------------------------------------------------------- Constructors
    
    
    /**
     * Construct a new LifecycleSupport object associated with the specified
     * Lifecycle component.
     *
     * @param lifecycle The Lifecycle component that will be the source
     *  of events that we fire
     */
    public LifecycleSupport(Lifecycle lifecycle) {
    
        super();
        this.lifecycle = lifecycle;
    
    }
    
    
    // ----------------------------------------------------- Instance Variables
    
    
    /**
     * The source component for lifecycle events that we will fire.
     */
    private Lifecycle lifecycle = null;
    
    
    /**
     * The set of registered LifecycleListeners for event notifications.
     */
    private LifecycleListener listeners[] = new LifecycleListener[0];
    
    private final Object listenersLock = new Object(); // Lock object for changes to listeners
    
    
    // --------------------------------------------------------- Public Methods
    
    
    /**
     * 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;
      }
    
    }
    
    
    /**
     * Get the lifecycle listeners associated with this lifecycle. If this 
     * Lifecycle has no listeners registered, a zero-length array is returned.
     */
    public LifecycleListener[] findLifecycleListeners() {
    
        return listeners;
    
    }
    
    
    /**
     * 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);
    
    }
    
    
    /**
     * Remove a lifecycle event listener from this component.
     *
     * @param listener The listener to remove
     */
    public void removeLifecycleListener(LifecycleListener listener) {
    
        synchronized (listenersLock) {
            int n = -1;
            for (int i = 0; i < listeners.length; i++) {
                if (listeners[i] == listener) {
                    n = i;
                    break;
                }
            }
            if (n < 0)
                return;
            LifecycleListener results[] =
              new LifecycleListener[listeners.length - 1];
            int j = 0;
            for (int i = 0; i < listeners.length; i++) {
                if (i != n)
                    results[j++] = listeners[i];
            }
            listeners = results;
        }
    
    }
    

    类名是final的无法继承,构造器需要传入Lifecycle实例,主要目的是为了初始化其成员变量lifecycle。类内部拥有3个成员变量分别是lifecycle,listeners,listenersLock。其中listeners是一个LifecycleListener类型的数组,专门用来防止内部所有的LifecycleListener实例,listenersLock是一个用来实现同步的锁。类有4个方法,我们依次来查看。

    • addLifecycleListener

        /**
         * Add a lifecycle event listener to this component.
         *
         * @param listener The listener to add
         */
        public void addLifecycleListener(LifecycleListener listener) {
      
          synchronized (listenersLock) {
        		//新建一个比listeners长度大1的新数组
              LifecycleListener results[] = new LifecycleListener[listeners.length + 1];
        		//遍历旧数组将其中旧的值一次赋给新数组
              for (int i = 0; i < listeners.length; i++)
                  results[i] = listeners[i];
        		//将入参传入添加到新数组中
              results[listeners.length] = listener;
        		//将listeners指向新数组
              listeners = results;
          }
      
        }
      

    该方法作用是添加指定的LifecycleListener实例。

    从代码可以看出,添加的方式是新建一个比之前listeners长度大1的数组,然后遍历listeners依次将旧数组的值赋予到对应新数组的位置,然后将方法入参传入的LifecycleListener实例赋值到数组的最后一个位置,最后将新的数组的引用赋给listeners成员变量,整个过程使用同步代码块实现,所以该方法是同步的,不会出现添加错误。

    • findLifecycleListeners

        /**
         * Get the lifecycle listeners associated with this lifecycle. If this 
         * Lifecycle has no listeners registered, a zero-length array is returned.
         */
        public LifecycleListener[] findLifecycleListeners() {
            return listeners;
        }
      

    该方法的作用是返回所有的生命周期监听器。

    查找方法比较简单直接返回 装了所有LifecycleListener实例的成员变量listeners

    • fireLifecycleEvent

         /**
         * 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 实例
            LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
        	//遍历所有的监听器 触发该LifecycleEvent
            LifecycleListener interested[] = listeners;
            for (int i = 0; i < interested.length; i++)
                interested[i].lifecycleEvent(event);
      
        }
      

    该方法的作用是触发指定的生命周期事件。

    方法的第一步根据传递的参数封装出了一个LifecycleEvent实例,实际上传递的String类型的type变量,它的所有的取值全部来之与Lifecycle接口中所定义的事件类型字符串,在上一篇文章中我们曾介绍过,读者可自行打开Lifecycle接口的源码进行查看。

    在新建LifecycleEvent实例的时候构造函数还传递了一个Lifecycle的实例,也就是类LifecycleSupport的构造器中传入的那个Lifecycle实例。也许有的人很奇怪为什么一定要传入一个Lifecycle实例,实际上在Catalina中在使用这个类的时候传入都是实现了Lifecycle接口的组件的实例对象,也就是说实际上传递的是每个需要被管理的组件的实例对象,因为他们都实现了Lifecycle接口,所以统一抽象为传入Lifecycle实例,这样就有个好处,因为组件很多,而大家都可以抽象为Lifecycle接口的实例,所以不需要在LifecycleEvent中做大量的判断是哪个组件的生命周期事件。

    源码的最后一步就是遍历所有的生命周期监听器,调用其lifecycleEvent方法。而lifecycleEvent这个方法在实现监听器的时候是需要实现的,所以可以在实现的方法中去对你所感兴趣的事件做出相应的处理。

    这个方法的流程就是 我现在到达了生命周期的A事件,那么我会把所有的生命周期监听器全部拉出来遍历一下,每个监听器都去调用下他的lifecycleEvent方法,如果有监听器正好对A事件做了判断(感兴趣),那么就会触发对应监听器的逻辑,从而达到监听的效果!

    • removeLifecycleListener

         /**
         * Remove a lifecycle event listener from this component.
         *
         * @param listener The listener to remove
         */
        public void removeLifecycleListener(LifecycleListener listener) {
      
            synchronized (listenersLock) {
                int n = -1;
                for (int i = 0; i < listeners.length; i++) {
                    if (listeners[i] == listener) {
                        n = i;
                        break;
                    }
                }
                if (n < 0)
                    return;
                LifecycleListener results[] = new LifecycleListener[listeners.length - 1];
                int j = 0;
                for (int i = 0; i < listeners.length; i++) {
                    if (i != n)
                        results[j++] = listeners[i];
                }
                listeners = results;
            }
      
        }
      

    该方法的作用是移除指定的生命周期监听器。

    源码比较简单应该很容易看懂,第一步遍历当前的listeners来查找指定listener,如果没找到就返回。第二步如果找到那么新建一个比当前listeners长度小1的数组,然后遍历除了查找到的指定的listener其他全部复制到新数组中,最后将成员变量listeners指向新数组的引用。最最后此方法使用了同步代码块,所以是线程安全的。

    LifecycleBase源码分析

    LifecycleBase的源码大致分两部分,一部分是关于LifecycleSupport,我们分开看下

    /**
     * Used to handle firing lifecycle events.
     * TODO: Consider merging LifecycleSupport into this class.
     */
    private LifecycleSupport lifecycle = new LifecycleSupport(this);
    
    
    /**
     * The current state of the source component.
     */
    private volatile LifecycleState state = LifecycleState.NEW;
    
    
    /**
     * {@inheritDoc}
     */
    @Override
    public void addLifecycleListener(LifecycleListener listener) {
        lifecycle.addLifecycleListener(listener);
    }
    
    
    /**
     * {@inheritDoc}
     */
    @Override
    public LifecycleListener[] findLifecycleListeners() {
        return lifecycle.findLifecycleListeners();
    }
    
    
    /**
     * {@inheritDoc}
     */
    @Override
    public void removeLifecycleListener(LifecycleListener listener) {
        lifecycle.removeLifecycleListener(listener);
    }
    
    
    /**
     * Allow sub classes to fire {@link Lifecycle} events.
     * 
     * @param type  Event type
     * @param data  Data associated with event.
     */
    protected void fireLifecycleEvent(String type, Object data) {
        lifecycle.fireLifecycleEvent(type, data);
    }
    

    可以很明显的看到,LifecycleBase这4个跟LifecycleSupport完全重名的方法都是使用成员变量lifecycle完成的,而lifecycle则是LifecycleBase的实例变量。

    LifecycleBase源码的第二部分是主要是实现接口Lifecycle定义的关于生命周期整体流程的4个方法init(),start(),stop(),destroy(),因为这4个方法在LifecycleBase内部实现的时候代码很相似,所以我们在这里只挑一个最典型的start()方法的实现来阅读源码,剩余的3个方法可以留给作者来自行查看。

    	 *            start()
     *  -----------------------------
     *  |                           |
     *  | init()                    |
     * NEW ->-- INITIALIZING        |
     * | |           |              |     ------------------<-----------------------
     * | |           |auto          |     |                                        |
     * | |          |/    start() |/   |/     auto          auto         stop() |
     * | |      INITIALIZED -->-- STARTING_PREP -->- STARTING -->- STARTED -->---  |
     * | |         |                                                            |  |
     * | |destroy()|                                                            |  |
     * | -->-----<--    ------------------------<--------------------------------  ^
     * |     |          |                                                          |
     * |     |         |/          auto                 auto              start() |
     * |     |     STOPPING_PREP ---->---- STOPPING ------>----- STOPPED ----->-----
     * |    |/                               ^                     |  ^
     * |     |               stop()           |                     |  |
     * |     |       --------------------------                     |  |
     * |     |       |                                              |  |
     * |     |       |    destroy()                       destroy() |  |
     * |     |    FAILED ---->------ DESTROYING ---<-----------------  |
     * |     |                        ^     |                          |
     * |     |     destroy()          |     |auto                      |
     * |     -------->-----------------    |/                         |
     * |                                 DESTROYED                     |
     * |                                                               |
     * |                            stop()                             |
     * --->------------------------------>------------------------------
    
    
     /**
     * The current state of the source component.
     */
    private volatile LifecycleState state = LifecycleState.NEW;
    
     /**
     * {@inheritDoc}
     */
    @Override
    public final synchronized void start() throws LifecycleException {
        
    	//1111111111111
        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;
        }
        
    	//22222222222
        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);
        }
    	//333333333333333
        setStateInternal(LifecycleState.STARTING_PREP, null, false);
    
        try {
    		//44444444444444
            startInternal();
        } 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);
        }
    	
    	//555555555555555
        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);
        }
    }
    

    在看代码之前,在Lifecycle接口中有一个用符号组成的图,表示了任何一个组件所有要经历的一个完整的生命周期流程,我们看代码的时候可以对照这个图来理解一些状态。

    在代码标注1的地方可以看到 先判断组件的当前处于的生命周期状态(state表示组件在声明周期中所处的状态,可以直接对应最上面图),如果是STARTING_PREPSTARTINGSTARTED,那么就打个日志就结束了。从最上面的生命周期流程图可以看到,当一个组件开始调用start()方法的时候,那么组件的状态应该是INITIALIZED,所以当组件是STARTING_PREPSTARTINGSTARTED这个3个的时候说明组件当前的状态是不对的所以直接就结束方法了。

    从代码标注2的地方,判断如果当前组件生命周期是NEW,那么就调用生命周期init()方法,如果是FAILED,表示组件启动失败就直接调用生命周期方法stop(),因为init(),stop(),destroy()start()同样都是平级的方法所以就不介绍了。继续看,如果当前组件生命周期状态不是INITIALIZED并且不是STOPPED这2个就调用invalidTransition()方法,从图上可以看到这2个状态是唯二正确的调用start()方法之前的组件该有的状态,如果不是这2个就调用invalidTransition()方法,我们来看下invalidTransition()方法源码。

    private void invalidTransition(String type) throws LifecycleException {
        String msg = sm.getString("lifecycleBase.invalidTransition", type,
                toString(), state);
        throw new LifecycleException(msg);
    }
    

    非常简单,invalidTransition()方法就是单纯抛个异常。所以总体代码2的意思就是 如果组件当前的生命周期是NEW或者FAIL还能抢救下,不是这两个并且还不是INITIALIZEDSTOPPED这2个合理的状态,那么连抢救都不需要抢救了,咱直接抛异常吧。

    在代码标注3的地方调用了setStateInternal()方法,我们查看下setStateInternal()方法的源码。

    private synchronized void setStateInternal(LifecycleState state,
        Object data, boolean check) throws LifecycleException {
    
    if (log.isDebugEnabled()) {
        log.debug(sm.getString("lifecycleBase.setState", this, state));
    }
    
    if (check) {
        // Must have been triggered by one of the abstract methods (assume
        // code in this class is correct)
        // null is never a valid state
        if (state == null) {
            invalidTransition("null");
            // Unreachable code - here to stop eclipse complaining about
            // a possible NPE further down the method
            return;
        }
        
        // Any method can transition to failed
        // startInternal() permits STARTING_PREP to STARTING
        // stopInternal() permits STOPPING_PREP to STOPPING and FAILED to
        // STOPPING
        if (!(state == LifecycleState.FAILED ||
                (this.state == LifecycleState.STARTING_PREP &&
                        state == LifecycleState.STARTING) ||
                (this.state == LifecycleState.STOPPING_PREP &&
                        state == LifecycleState.STOPPING) ||
                (this.state == LifecycleState.FAILED &&
                        state == LifecycleState.STOPPING))) {
            // No other transition permitted
            invalidTransition(state.name());
        }
    }
    
    this.state = state;
    String lifecycleEvent = state.getLifecycleEvent();
    if (lifecycleEvent != null) {
        fireLifecycleEvent(lifecycleEvent, data);
    }
    }
    

    代码还是很简单的,主要作用就是把当前组件的状态设置成入参state的状态,根据传递的参数来判断是否要检查当前组件的状态是否符合要求,最后触发下当前生命周期状态对应的生命周期事件,调用下fireLifecycleEvent来启动下所有的监听器。注意此方法是同步的。

    在代码4标注的地方调用了startInternal()方法,我们看下startInternal()

        /**
     * Sub-classes must ensure that the state is changed to
     * {@link LifecycleState#STARTING} during the execution of this method.
     * Changing state will trigger the {@link Lifecycle#START_EVENT} event.
     * 
     * If a component fails to start it may either throw a
     * {@link LifecycleException} which will cause it's parent to fail to start
     * or it can place itself in the error state in which case {@link #stop()}
     * will be called on the failed component but the parent component will
     * continue to start normally.
     * 
     * @throws LifecycleException
     */
    protected abstract void startInternal() throws LifecycleException;
    

    因为LifecycleBase类是一个抽象类所以也可以拥有抽象方法。而startInternal()就是一个抽象方法,这个方法由所有继承LifecycleBase类的组件去实现。其实也非常好理解,start()方法是所有组件都要执行的动作,但是所有组件在启动的时候都会做一些动作,比如检查当前组件状态,触发当前生命周期对应的监听器,但是每个组件在启动的时候也许还是需要做一些特殊的动作,组件特有的动作,所以在把这些共同的动作都抽象到LifecycleBase类的start()方法中,而组件特殊的动作在继承LifecycleBase类后就写在需要复写的startInternal()方法中。所以startInternal()方法设计成抽象方法,需要子类实现。其实这种代码的模式使用的是设计模式中的模版设计模式,这个我们在后面的文章中会总结。

    在代码5标注的地方,我们看到了又对组件的状态的判断,和代码2的地方比较类似,只不过代码2是在启动之前的判断,而代码5则是在启动之后(调用子类的启动方法)进行组件状态的检查,简单查看下,总结如下:如果组件启动失败(FAILED),调用stop()方法,如果组件状态不是STARTING(在3的地方将组件状态设置成STARTING_PREP,一般会在子类复写的startInternal()方法中将组件状态设置成STARTING),那么直接抛异常,否则(此时组件是正常启动,状态是STARTING)将组件设置成STARTED状态。

    start()方法分析完了,可以看出基本就是对组件状态的检查修改以及调用子类实现的startInternal()方法,当启动成功以后继续修改组件的状态,其实就是按照最开始的那个图来走流程,而其他三个方法init(),stop(),destroy()基本思想都是一样的。

    读到这里,也许有读者还是很疑惑大概知道了生命周期管理中所有类所处的位置以及作用,但是还是对Catalina中生命周期的运作方式感觉到迷糊,下篇文章我们将举例分析Catalina中生命周期的运作方式!让读者彻底搞懂其原理。

  • 相关阅读:
    python 进程通信,共享变量
    使用 curl 和 xargs 命令批量删除 ES索引,并将一些不想删除的索引过滤出来
    Spark Over Yarn 发现输出到kafka报错: topic not present on metadata after x
    ES 同台机器多实例报 master not discovered or elected yet
    ES数据写入时间格式问题
    Kibana 发现数据时间不对
    python包部署到服务器上报 cannot find module error
    好久没写博客了,。。。。。
    linux 修改 elf 文件的dynamic linker 和 rpath
    linux 进程 进程组 作业 会话 控制终端
  • 原文地址:https://www.cnblogs.com/coldridgeValley/p/5816405.html
Copyright © 2011-2022 走看看