zoukankan      html  css  js  c++  java
  • 深入浅出Tomcat/3

    在上面的部分,其实我们已经接触到Tomcat的生命周期了,接下来我们将仔细讨论和学习Tomcat的生命周期的具体实现。

    LifeCycle接口

    这个LifeCycle接口上面在讲解Server和Service时其实已经有所接触。Tomcat通过org.apache.catalina.LifeCycle接口统一接管Tomcat的生命周期,所有继承自它的组件(即Component)都需要实现这个接口。

    我们先俯视看一看LifeCycle接口的定义。

    根据上图,我们清晰看到上图包含了4个生命周期的方法:
    1. init
    2. start
    3. stop
    4. destroy
    这4个方法不用多解释,很直观,我们前面也有所接触。

    同时,每个方法又定义了几个常量字符串,用于LifeCycleEvent事件的type属性,用来描述各个状态的变化。举个例子,对于init周期,它包含before_init和 after_init两个字符串,其他类似。

    它同时也定义了三个管理监听器的方法,分别如下:
    • addLifeCycleListener
    • findLifeCycleListeners
    • removeLifeCycleListener
    显而易见,它们用来增加、查找和删除生命周期的监听器。

    最后定义了获取当前状态信息,用2个方法实现:
    • getState
    • getStateName
    getState返回的是LifeCycleState,而且LifeCycleState是一个枚举类型。如下

    public enum LifecycleState {
        NEW(false, null),
        INITIALIZING(false, Lifecycle.BEFORE_INIT_EVENT),
        INITIALIZED(false, Lifecycle.AFTER_INIT_EVENT),
        STARTING_PREP(false, Lifecycle.BEFORE_START_EVENT),
        STARTING(true, Lifecycle.START_EVENT),
        STARTED(true, Lifecycle.AFTER_START_EVENT),
        STOPPING_PREP(true, Lifecycle.BEFORE_STOP_EVENT),
        STOPPING(false, Lifecycle.STOP_EVENT),
        STOPPED(false, Lifecycle.AFTER_STOP_EVENT),
        DESTROYING(false, Lifecycle.BEFORE_DESTROY_EVENT),
        DESTROYED(false, Lifecycle.AFTER_DESTROY_EVENT),
        FAILED(false, null);

    我们看到它列举了Tomcat各个生命周期。

    LifeCycleBase类

    LifeCycleBase是实现了LifeCycle的抽象类,Tomcat的几个生命周期的管理都交给它,所以弄清楚这个类的实现,基本上也就明白了Tomcat的生命周期了。

    在LifeCycle接口里,我们提到的4个周期的方法以及3个监听器的管理方法,最后还有2个获取状态信息的方法,我们接下来逐一分析和了解。

    4个生命周期方法

    方法init

    public final synchronized void init() throws LifecycleException {
    if (!state.equals(LifecycleState.NEW)) {
    invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
    }
    
    try {
    setStateInternal(LifecycleState.INITIALIZING, null, false);
    initInternal();
    setStateInternal(LifecycleState.INITIALIZED, null, false);
    } catch (Throwable t) {
    handleSubClassException(t, "lifecycleBase.initFail", toString());
    }
    }

    先判断当前状态是不是NEW,如果不是抛出异常。因为init时,代表的是Tomcat的初始化,所以其状态需要为NEW的。接下来就是设置状态为LifecycleState.INITIALIZING,也就是正在初始化,然后调用initInternal开始初始化了,初始化完之后设置为LifecycleState.INITIALIZED

    这里需要多说一下invalidTransition这个方法,因为后面很多地方都会用到它。

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

    我们看到invalidTransition方法其实没做其他事情,就是抛出了一个异常而已。
    同时,也介绍一下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);
    }
    }

    变量check是传进来的,是否要检查。至于后面的逻辑注释写的比较清楚,不符合逻辑的状态转化都会报错,不多解释。

    后面的fireLifeCycleEvent的代码如下:

    protected void fireLifecycleEvent(String type, Object data) {
    LifecycleEvent event = new LifecycleEvent(this, type, data);
    for (LifecycleListener listener : lifecycleListeners) {
    listener.lifecycleEvent(event);
    }
    }

    也是很简单,就是让LifeCycle的事件监听者触发事件,至于如何去使用这些event,则是每个监听者自己的业务逻辑了。这也符合一贯的代码实现方法,如果有多个监听器,然后逐一触发这些监听器,这其实是事件监听最基本的实现方法。

    以上就是init的方法实现。

    方法start
    直接上代码

    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.
    handleSubClassException(t, "lifecycleBase.startFail", toString());
    }
    }

    第一步就是检查状态的合理性,如果已经在准备或者开始了,直接抛出已经开始的exception。如果是NEW的话,说明init这一步没有做,那就初始化一下。
    正式开始启动了,首先需要将状态设置为LifecycleState.STARTING_PREP,接下调用startInternal开始启动。执行完startInternal后验证state,如果状态不对,要么停止,要么抛出异常。

    方法destroy
    destroy其实调用的是stop方法。

    方法stop
    Stop方法

    public final synchronized void stop() throws LifecycleException {
    
    if (LifecycleState.STOPPING_PREP.equals(state) || LifecycleState.STOPPING.equals(state) ||
    LifecycleState.STOPPED.equals(state)) {
    
    if (log.isDebugEnabled()) {
    Exception e = new LifecycleException();
    log.debug(sm.getString("lifecycleBase.alreadyStopped", toString()), e);
    } else if (log.isInfoEnabled()) {
    log.info(sm.getString("lifecycleBase.alreadyStopped", toString()));
    }
    
    return;
    }
    
    if (state.equals(LifecycleState.NEW)) {
    state = LifecycleState.STOPPED;
    return;
    }
    
    if (!state.equals(LifecycleState.STARTED) && !state.equals(LifecycleState.FAILED)) {
    invalidTransition(Lifecycle.BEFORE_STOP_EVENT);
    }
    
    try {
    if (state.equals(LifecycleState.FAILED)) {
    // Don't transition to STOPPING_PREP as that would briefly mark the
    // component as available but do ensure the BEFORE_STOP_EVENT is
    // fired
    fireLifecycleEvent(BEFORE_STOP_EVENT, null);
    } else {
    setStateInternal(LifecycleState.STOPPING_PREP, null, false);
    }
    
    stopInternal();
    
    // Shouldn't be necessary but acts as a check that sub-classes are
    // doing what they are supposed to.
    if (!state.equals(LifecycleState.STOPPING) && !state.equals(LifecycleState.FAILED)) {
    invalidTransition(Lifecycle.AFTER_STOP_EVENT);
    }
    
    setStateInternal(LifecycleState.STOPPED, null, false);
    } catch (Throwable t) {
    handleSubClassException(t, "lifecycleBase.stopFail", toString());
    } finally {
    if (this instanceof Lifecycle.SingleUse) {
    // Complete stop process first
    setStateInternal(LifecycleState.STOPPED, null, false);
    destroy();
    }
    }
    }

    首先,检查一下当前状态,如果当前状态为与STOP相关的几个状态,则抛出已经停止的异常。如果为NEW,说明还没有初始化,直接将STOPPED的状态赋值一下即可。如果状态不是STARTED,是不可以停止的,这个时候直接抛出异常。将触发的event给监听器和前面类似,不多做解释。

    3个关于监听器的方法

    前面介绍到LifeCycleBase有三个方法来管理监听器:
    • addLifeCycleListener
    • findLifeCycleListeners
    • removeLifeCycleListener
    我们看看它们的实现。

    @Override
    public void addLifecycleListener(LifecycleListener listener) {
    lifecycleListeners.add(listener);
    }
    
    
    /**
    * {@inheritDoc}
    */
    @Override
    public LifecycleListener[] findLifecycleListeners() {
    return lifecycleListeners.toArray(new LifecycleListener[0]);
    }
    
    
    /**
    * {@inheritDoc}
    */
    @Override
    public void removeLifecycleListener(LifecycleListener listener) {
    lifecycleListeners.remove(listener);
    }

    代码比较简单了,但是需要注意的是lifecycleListeners是一个CopyOnWriteArrayList。

    private final List<LifecycleListener> lifecycleListeners = new CopyOnWriteArrayList<>();

    关于CopyOnWriteArrayList,它继承了ArrayList。我们都知道ArrayList不是线程安全的,但CopyOnWriteArrayList则是线程安全的。

    /**
    * Creates a list containing the elements of the specified
    * collection, in the order they are returned by the collection's
    * iterator.
    *
    * @param c the collection of initially held elements
    * @throws NullPointerException if the specified collection is null
    */
    public CopyOnWriteArrayList(Collection<? extends E> c) {
    Object[] elements;
    if (c.getClass() == CopyOnWriteArrayList.class)
    elements = ((CopyOnWriteArrayList<?>)c).getArray();
    else {
    elements = c.toArray();
    // c.toArray might (incorrectly) not return Object[] (see 6260652)
    if (elements.getClass() != Object[].class)
    elements = Arrays.copyOf(elements, elements.length, Object[].class);
    }
    setArray(elements);
    }

    我们可以看到代码行

    elements = c.toArray();

    它其实是Copy一份c,这种开销是很大的。尽管开销很大,但是当遍历操作的数量大大超过可变操作的数量时,这种方法可能比其他替代方法更有效。
    同时,在add和remove时,我们看到使用到ReentrantLock来保证线程安全。
    CopyOnWriteArray比较适用于读多修改少的情景。在Tomcat这里,一般来说Listener都是在Server.xml,如果在想增加或删除Listener,必须重新启动Tomcat,在这种场景下,其实正好符合读多写少这种特征。

    public void add(int index, E element) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
    Object[] elements = getArray();
    int len = elements.length;
    if (index > len || index < 0)
    throw new IndexOutOfBoundsException("Index: "+index+
    ", Size: "+len);
    Object[] newElements;
    int numMoved = len - index;
    if (numMoved == 0)
    newElements = Arrays.copyOf(elements, len + 1);
    else {
    newElements = new Object[len + 1];
    System.arraycopy(elements, 0, newElements, 0, index);
    System.arraycopy(elements, index, newElements, index + 1,
    numMoved);
    }
    newElements[index] = element;
    setArray(newElements);
    } finally {
    lock.unlock();
    }
    }
    
    /**
    * Removes the element at the specified position in this list.
    * Shifts any subsequent elements to the left (subtracts one from their
    * indices). Returns the element that was removed from the list.
    *
    * @throws IndexOutOfBoundsException {@inheritDoc}
    */
    public E remove(int index) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
    Object[] elements = getArray();
    int len = elements.length;
    E oldValue = get(elements, index);
    int numMoved = len - index - 1;
    if (numMoved == 0)
    setArray(Arrays.copyOf(elements, len - 1));
    else {
    Object[] newElements = new Object[len - 1];
    System.arraycopy(elements, 0, newElements, 0, index);
    System.arraycopy(elements, index + 1, newElements, index,
    numMoved);
    setArray(newElements);
    }
    return oldValue;
    } finally {
    lock.unlock();
    }
    }

    获取状态

    @Override
    public LifecycleState getState() {
    return state;
    }
    
    
    /**
    * {@inheritDoc}
    */
    @Override
    public String getStateName() {
    return getState().toString();
    }

    代码非常简单,不介绍了。

  • 相关阅读:
    Winform打包Exe Inno Setup
    electron build慢
    electron解压app.asar文件
    input readonly 禁止获得焦点 和选择
    JS export
    数据库插件 red-gate SQLToolbelt
    DataGridView修改值后,最后一个修改项页面不会刷新
    DbDataReaderExtensions DbDataRender转换为实体
    反射获得实体
    LINQ Expression AndAlso,OrElse和And,Or的区别
  • 原文地址:https://www.cnblogs.com/confach/p/10308572.html
Copyright © 2011-2022 走看看