目录

  • 什么是Lifecycle?
  • Lifecycle方法
  • LifecycleBase
    • 增加、删除和获取监听器
    • init()
    • start()
    • stop()
    • destroy()
    • 模板方法
  • 总结

前言

Tomcat里面有各种各样的组件,每个组件各司其职,组件之间又相互协作共同完成web服务器这样的工程。在这些组件之上,Lifecycle(生命周期机制)至关重要!在学习各个组件之前,我们需要看看Lifecycle是什么以及能做什么?实现原理又是怎样的?

什么是Lifecycle?

Lifecycle,其实就是一个状态机,对组件的由生到死状态的管理。

当组件在STARTING_PREP、STARTING或STARTED时,调用start()方法没有任何效果

当组件在NEW状态时,调用start()方法会导致init()方法被立刻执行,随后start()方法被执行

当组件在STOPPING_PREP、STOPPING或STOPPED时,调用stop()方法没有任何效果

当一个组件在NEW状态时,调用stop()方法会将组件状态变更为STOPPED,比较典型的场景就是组件启动失败,其子组件还没有启动。当一个组件停止的时候,它将尝试停止它下面的所有子组件,即使子组件还没有启动。

Lifecycle方法

我们看看Lifecycle有哪些方法,如下所示:

public interface Lifecycle {
    // 添加监听器
    public void addLifecycleListener(LifecycleListener listener);
    // 获取所以监听器
    public LifecycleListener[] findLifecycleListeners();
    // 移除某个监听器
    public void removeLifecycleListener(LifecycleListener listener);
    // 初始化方法
    public void init() throws LifecycleException;
    // 启动方法
    public void start() throws LifecycleException;
    // 停止方法,和start对应
    public void stop() throws LifecycleException;
    // 销毁方法,和init对应
    public void destroy() throws LifecycleException;
    // 获取生命周期状态
    public LifecycleState getState();
    // 获取字符串类型的生命周期状态
    public String getStateName();
}

LifecycleBase

LifecycleBase是Lifecycle的基本实现。我们逐一来看Lifecycle的各个方法。

增加、删除和获取监听器

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

@Override
public void addLifecycleListener(LifecycleListener listener) {
    lifecycleListeners.add(listener);
}
@Override
public LifecycleListener[] findLifecycleListeners() {
    return lifecycleListeners.toArray(new LifecycleListener[0]);
}
@Override
public void removeLifecycleListener(LifecycleListener listener) {
    lifecycleListeners.remove(listener);
}
  1. 生命周期监听器保存在一个线程安全的List中,CopyOnWriteArrayList。所以add和remove都是直接调用此List的相应方法。
  2. findLifecycleListeners返回的是一个数组,为了线程安全,所以这儿会生成一个新数组。

init()方法

@Override
public final synchronized void init() throws LifecycleException {
    // 非NEW状态,不允许调用init()方法
    if (!state.equals(LifecycleState.NEW)) {
        invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
    }

    try {
        // 初始化逻辑之前,先将状态变更为`INITIALIZING`
        setStateInternal(LifecycleState.INITIALIZING, null, false);
        // 初始化,该方法为一个abstract方法,需要组件自行实现
        initInternal();
        // 初始化完成之后,状态变更为`INITIALIZED`
        setStateInternal(LifecycleState.INITIALIZED, null, false);
    } catch (Throwable t) {
        // 初始化的过程中,可能会有异常抛出,这时需要捕获异常,并将状态变更为`FAILED`
        ExceptionUtils.handleThrowable(t);
        setStateInternal(LifecycleState.FAILED, null, false);
        throw new LifecycleException(
                sm.getString("lifecycleBase.initFail",toString()), t);
    }
}

setStateInternal方法用于维护状态,同时在状态转换成功之后触发事件。为了状态的可见性,所以state声明为volatile类型的。

private volatile LifecycleState state = LifecycleState.NEW;。
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
        // state不允许为null
        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);
    }
}

我们看看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);
}

首先, 创建一个事件对象, 然通知所有的监听器发生了该事件.并做响应.

start()方法

@Override
public final synchronized void start() throws LifecycleException {
   // `STARTING_PREP`、`STARTING`和`STARTED时,将忽略start()逻辑
   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;
   }

   // `NEW`状态时,执行init()方法
   if (state.equals(LifecycleState.NEW)) {
       init();
   }

   // `FAILED`状态时,执行stop()方法
   else if (state.equals(LifecycleState.FAILED)) {
       stop();
   }

   // 不是`INITIALIZED`和`STOPPED`时,则说明是非法的操作
   else if (!state.equals(LifecycleState.INITIALIZED) &&
           !state.equals(LifecycleState.STOPPED)) {
       invalidTransition(Lifecycle.BEFORE_START_EVENT);
   }

   try {
       // start前的状态设置
       setStateInternal(LifecycleState.STARTING_PREP, null, false);
       // start逻辑,抽象方法,由组件自行实现
       startInternal();
       // start过程中,可能因为某些原因失败,这时需要stop操作
       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 {
           // 设置状态为STARTED
           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);
   }
}

stop()方法

@Override
public final synchronized void stop() throws LifecycleException {
    // `STOPPING_PREP`、`STOPPING`和STOPPED时,将忽略stop()的执行
    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;
    }

    // `NEW`状态时,直接将状态变更为`STOPPED`
    if (state.equals(LifecycleState.NEW)) {
        state = LifecycleState.STOPPED;
        return;
    }

    // stop()的执行,必须要是`STARTED`和`FAILED`
    if (!state.equals(LifecycleState.STARTED) && !state.equals(LifecycleState.FAILED)) {
        invalidTransition(Lifecycle.BEFORE_STOP_EVENT);
    }

    try {
        // `FAILED`时,直接触发BEFORE_STOP_EVENT事件
        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 {
            // 设置状态为STOPPING_PREP
            setStateInternal(LifecycleState.STOPPING_PREP, null, false);
        }

        // stop逻辑,抽象方法,组件自行实现
        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);
        }
        // 设置状态为STOPPED
        setStateInternal(LifecycleState.STOPPED, null, false);
    } catch (Throwable t) {
        ExceptionUtils.handleThrowable(t);
        setStateInternal(LifecycleState.FAILED, null, false);
        throw new LifecycleException(sm.getString("lifecycleBase.stopFail",toString()), t);
    } finally {
        if (this instanceof Lifecycle.SingleUse) {
            // Complete stop process first
            setStateInternal(LifecycleState.STOPPED, null, false);
            destroy();
        }
    }
}

destroy()方法

@Override
public final synchronized void destroy() throws LifecycleException {
    // `FAILED`状态时,直接触发stop()逻辑
    if (LifecycleState.FAILED.equals(state)) {
        try {
            // Triggers clean-up
            stop();
        } catch (LifecycleException e) {
            // Just log. Still want to destroy.
            log.warn(sm.getString(
                    "lifecycleBase.destroyStopFail", toString()), e);
        }
    }

    // `DESTROYING`和`DESTROYED`时,忽略destroy的执行
    if (LifecycleState.DESTROYING.equals(state) ||
            LifecycleState.DESTROYED.equals(state)) {

        if (log.isDebugEnabled()) {
            Exception e = new LifecycleException();
            log.debug(sm.getString("lifecycleBase.alreadyDestroyed", toString()), e);
        } else if (log.isInfoEnabled() && !(this instanceof Lifecycle.SingleUse)) {
            // Rather than have every component that might need to call
            // destroy() check for SingleUse, don't log an info message if
            // multiple calls are made to destroy()
            log.info(sm.getString("lifecycleBase.alreadyDestroyed", toString()));
        }

        return;
    }

    // 非法状态判断
    if (!state.equals(LifecycleState.STOPPED) &&
            !state.equals(LifecycleState.FAILED) &&
            !state.equals(LifecycleState.NEW) &&
            !state.equals(LifecycleState.INITIALIZED)) {
        invalidTransition(Lifecycle.BEFORE_DESTROY_EVENT);
    }

    try {
        // destroy前状态设置
        setStateInternal(LifecycleState.DESTROYING, null, false);
       // 抽象方法,组件自行实现
        destroyInternal();
        // destroy后状态设置
        setStateInternal(LifecycleState.DESTROYED, null, false);
    } catch (Throwable t) {
        ExceptionUtils.handleThrowable(t);
        setStateInternal(LifecycleState.FAILED, null, false);
        throw new LifecycleException(
                sm.getString("lifecycleBase.destroyFail",toString()), t);
    }
}

模板方法

从上述源码看得出来,LifecycleBase是使用了状态机+模板模式来实现的。模板方法有下面这几个:

// 初始化方法
protected abstract void initInternal() throws LifecycleException;
// 启动方法
protected abstract void startInternal() throws LifecycleException;
// 停止方法
protected abstract void stopInternal() throws LifecycleException;
// 销毁方法
protected abstract void destroyInternal() throws LifecycleException;

总结

Lifecycle其实非常简单,代码也不复杂,但是剖析其实现对于我们理解组件的生命周期有很大的帮助,也有助于我们对设计模式的回顾。

Tomcat源码分析 | 一文详解生命周期机制Lifecycle的更多相关文章

  1. 【集合框架】JDK1.8源码分析之ArrayList详解(一)

    [集合框架]JDK1.8源码分析之ArrayList详解(一) 一. 从ArrayList字表面推测 ArrayList类的命名是由Array和List单词组合而成,Array的中文意思是数组,Lis ...

  2. nginx源码分析线程池详解

    nginx源码分析线程池详解 一.前言     nginx是采用多进程模型,master和worker之间主要通过pipe管道的方式进行通信,多进程的优势就在于各个进程互不影响.但是经常会有人问道,n ...

  3. vuex 源码分析(六) 辅助函数 详解

    对于state.getter.mutation.action来说,如果每次使用的时候都用this.$store.state.this.$store.getter等引用,会比较麻烦,代码也重复和冗余,我 ...

  4. vuex 源码分析(五) action 详解

    action类似于mutation,不同的是Action提交的是mutation,而不是直接变更状态,而且action里可以包含任意异步操作,每个mutation的参数1是一个对象,可以包含如下六个属 ...

  5. Linux进程调度与源码分析(二)——进程生命周期与task_struct进程结构体

    1.进程生命周期 Linux操作系统属于多任务操作系统,系统中的每个进程能够分时复用CPU时间片,通过有效的进程调度策略实现多任务并行执行.而进程在被CPU调度运行,等待CPU资源分配以及等待外部事件 ...

  6. Golang源码分析之目录详解

    开源项目「go home」聚焦Go语言技术栈与面试题,以协助Gopher登上更大的舞台,欢迎go home~ 导读 学习Go语言源码的第一步就是了解先了解它的目录结构,你对它的源码目录了解多少呢? 目 ...

  7. Tomcat源码分析 (十)----- 彻底理解 Session机制

    Tomcat Session 概述 首先 HTTP 是一个无状态的协议, 这意味着每次发起的HTTP请求, 都是一个全新的请求(与上个请求没有任何联系, 服务端不会保留上个请求的任何信息), 而 Se ...

  8. Java 容器源码分析之集合类详解

    集合类说明及区别 Collection ├List │├LinkedList │├ArrayList │└Vector │ └Stack └Set Map ├Hashtable ├HashMap └W ...

  9. Cloudera Impala源码分析: SimpleScheduler调度策略详解包括作用、接口及实现等

    问题导读:1.Scheduler任务中Distributed Plan.Scan Range是什么?2.Scheduler基本接口有哪些?3.QuerySchedule这个类如何理解?4.Simple ...

随机推荐

  1. Centos 8 阿里yum源配置

    编辑 CentOS-AppStream.repo配置文件,注释原有url,加入以下url baseurl=https://mirrors.aliyun.com/centos/$releasever/A ...

  2. Python常用的数据文件存储的4种格式(txt/json/csv/excel)及操作Excel相关的第三方库(xlrd/xlwt/pandas/openpyxl)(2021最新版)

    序言:保存数据的方式各种各样,最简单的方式是直接保存为文本文件,如TXT.JSON.CSV等,除此之外Excel也是现在比较流行的存储格式,通过这篇文章你也将掌握通过一些第三方库(xlrd/xlwt/ ...

  3. Java第三天【变量、常量、数据类型】

    学习Java第三天!加油!请帖友看看有和不足的地方,和在下说一下,谢谢! 变量 变量(variable): 1.变量的本质就是代表"可操作的存储空间",空间位置是确定的,蛋里面放置 ...

  4. Bootstrap-2栅格系统

    栅格系统(使用最新版本bootstrap) Grid options(网格配置) Responsive classes(响应式class) Gutters(间距) Alignment(对齐方式) Re ...

  5. 问题 G: 心急的C小加

    题目描述 C小加有一些木棒,它们的长度和质量都已经知道,需要一个机器处理这些木棒,机器开启的时候需要耗费一个单位的时间,如果第i+1个木棒的重量和长度都大于等于第i个处理的木棒,那么将不会耗费时间,否 ...

  6. Vue组件传值prop验证方式

    在Vue组件开发过程中,父组件要经常给子组件传递数据,在传递数据的过程中,子组件可以使用prop来接收父组件传递的值,同时呢,我们可以为组件的 prop 指定验证要求,例如你知道的这些类型.如果有一个 ...

  7. 如何将rabbitmq集群中的某个节点移除.

    首先将要移除的节点停机. root@rabbitmq-03:~# rabbitmqctl stop Stopping and halting node 'rabbit@rabbitmq-03' ... ...

  8. Python介绍和安装

    python介绍和安装 目录 python介绍和安装 1. Python简介 2. 解释器 2.1 Python解释器的种类 2.2 Python解释器版本 3. Windows下安装Python 3 ...

  9. ICCV2021 | Vision Transformer中相对位置编码的反思与改进

    ​前言  在计算机视觉中,相对位置编码的有效性还没有得到很好的研究,甚至仍然存在争议,本文分析了相对位置编码中的几个关键因素,提出了一种新的针对2D图像的相对位置编码方法,称为图像RPE(IRPE). ...

  10. 看动画学算法之:hashtable

    目录 简介 散列表的关键概念 数组和散列表 数组的问题 hash的问题 线性探测 二次探测 双倍散列 分离链接 rehash 简介 java中和hash相关并且常用的有两个类hashTable和has ...