Tomcat源码解析(三):LifeCycle生命周期管理

news2024/10/22 13:55:47

Tomcat源码系列文章

Tomcat源码解析(一):Tomcat整体架构

Tomcat源码解析(二):Bootstrap和Catalina

Tomcat源码解析(三):LifeCycle生命周期管理


目录

  • 前言
  • 一、LifeCycle接口
    • 1、接口介绍
    • 2、生命周期状态
  • 二、LifecycleBase抽象类
    • 1、监听器
    • 2、init
    • 3、start
    • 4、stop
    • 5、destroy
  • 总结

前言

  • 在前文中我们介绍了tomcat的启动类加载
  • 核心内容就是getServer().init()组件的初始化getServer().start()启动服务
  • 由于所有的组件均存在初始化启动停止等生命周期方法,拥有生命周期管理的特性
  • 基于生命周期管理抽象成了一个接口Lifecycle
  • 组件Server、Service、Container、Executor、Connector组件,都实现生命周期的接口

在这里插入图片描述

一、LifeCycle接口

1、接口介绍

  • LifeCycle接口内容可以分为三类:监听器处理生命周期方法生命周期状态
  • 各个组件都有个生命周期状态,在执行生命周期方法后产生变化,可以通过getState方法来获取
  • 一个组件在状态变化时可以通过被注册在其上的监听器触发一些处理操作
public interface Lifecycle {
    /** 第1类:监听器处理 **/
    // 添加监听器
    public void addLifecycleListener(LifecycleListener listener);
    // 获取所以监听器
    public LifecycleListener[] findLifecycleListeners();
    // 移除某个监听器
    public void removeLifecycleListener(LifecycleListener listener);
    
    /** 第2类:生命周期方法 **/
    // 初始化方法
    public void init() throws LifecycleException;
    // 启动方法
    public void start() throws LifecycleException;
    // 停止方法,和start对应
    public void stop() throws LifecycleException;
    // 销毁方法,和init对应
    public void destroy() throws LifecycleException;
    
    /** 第3类:生命周期状态 **/
    // 获取生命周期状态
    public LifecycleState getState();
    // 获取字符串类型的生命周期状态
    public String getStateName();
}

2、生命周期状态

  • 在枚举类LifecycleState里Tomcat给各个组件定义了一些生命周期中的状态
  • 每个状态都有一个lifecycleEvent参数,在监听器的时候会用到
public enum LifecycleState {
	// 容器刚刚创建时,即在LifecycleBase实例构造完成时的状态
    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);
 
    private final boolean available;
    private final String lifecycleEvent;
 
    LifecycleState(boolean available, String lifecycleEvent) {
        this.available = available;
        this.lifecycleEvent = lifecycleEvent;
    }
 
    public boolean isAvailable() {
        return available;
    }
 
    public String getLifecycleEvent() {
        return lifecycleEvent;
    }
}
  • 这些状态主要用于对组件进行管控,现在只需要知道这些组件都有自己的生命周期状态且可以进行转换即可

在这里插入图片描述
特别说明:所有的状态都可以可以转换为FAILED状态

二、LifecycleBase抽象类

  • LifecycleBase抽象类是Lifecycle接口的基本实现

1、监听器

  • 生命周期监听器保存在一个线程安全的CopyOnWriteArrayList中
  • 所以add和remove都是直接调用此List的相应方法
  • findLifecycleListeners方法:返回的是一个数组,为了线程安全,所以这儿会生成一个新数组
  • fireLifecycleEvent方法:允许子类触发生命周期事件
public abstract class LifecycleBase implements 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);
	}
	
	// 触发生命周期事件
	protected void fireLifecycleEvent(String type, Object data) {
	    LifecycleEvent event = new LifecycleEvent(this, type, data);
	    for (LifecycleListener listener : lifecycleListeners) {
	        listener.lifecycleEvent(event);
	    }
	}
}

2、init

  • 基本流程就是状态切换,切换过程中的具体操作留给子类(即我们的各个组件如server、service等)去实现
@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);
    }
}
// 真正的初始化方法,需要子类实现此方法
protected abstract void initInternal() throws LifecycleException;
  • setStateInternal方法用于维护状态,同时在状态转换成功之后触发事件
  • 为了状态的可见性,所以state声明为volatile类型的
private volatile LifecycleState state = LifecycleState.NEW;private synchronized void setStateInternal(LifecycleState state,
        Object data, boolean check) throws LifecycleException {
    // 是否校验状态,一般初始化启动流程这里都是false
    if (check) {
        // state不允许为null
        if (state == null) {
        	// 抛异常
            invalidTransition("null");
            return;
        }
        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))) {
            invalidTransition(state.name());
        }
    }
    // 设置状态
    this.state = state;
    // 触发事件
    String lifecycleEvent = state.getLifecycleEvent();
    if (lifecycleEvent != null) {
        fireLifecycleEvent(lifecycleEvent, data);
    }
}
  • 设置完 state 的状态之后,就触发该状态的事件了,通知事件监听器
  • 这里的LifecycleListener对象是在Catalina对象解析server.xml文件时就已经创建好并加到lifecycleListeners里的
private final List<LifecycleListener> lifecycleListeners = new CopyOnWriteArrayList<>();
 
protected void fireLifecycleEvent(String type, Object data) {
    LifecycleEvent event = new LifecycleEvent(this, type, data);
    for (LifecycleListener listener : lifecycleListeners) {
        listener.lifecycleEvent(event);
    }
}

3、start

  • start和init类似,先做校验后切换状态,具体start操作留给子类实现
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)) {
        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);
    }
 
 	// 一般流程会走到这里,刚走完初始化流程,状态为INITIALIZED(初始化完成状态)
    try {
        // start前的状态设置
        setStateInternal(LifecycleState.STARTING_PREP, null, false);
        // start逻辑,抽象方法,由组件自行实现
        startInternal();
        // start过程中,可能因为某些原因失败,这时需要stop操作
        if (state.equals(LifecycleState.FAILED)) {
            stop();
        } else if (!state.equals(LifecycleState.STARTING)) {
        	// 抛出异常
            invalidTransition(Lifecycle.AFTER_START_EVENT);
        } else {
            // 设置状态为STARTED(启动完成状态)
            setStateInternal(LifecycleState.STARTED, null, false);
        }
    } catch (Throwable t) {
        ExceptionUtils.handleThrowable(t);
        // 异常状态
        setStateInternal(LifecycleState.FAILED, null, false);
        throw new LifecycleException(sm.getString("lifecycleBase.startFail", toString()), t);
    }
}

4、stop

  • stop和start类似,先做校验后切换状态,具体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);
    }

 	// 一般流程会走到这里,走完启动流程,状态为STARTED(启动完成状态)
    try {
        // `FAILED`时,直接触发BEFORE_STOP_EVENT事件
        if (state.equals(LifecycleState.FAILED)) {
            fireLifecycleEvent(BEFORE_STOP_EVENT, null);
        } 
        // 设置状态为STOPPING_PREP(停止前)
        else {
            setStateInternal(LifecycleState.STOPPING_PREP, null, false);
        }

        // stop逻辑,抽象方法,组件自行实现
        stopInternal();

        // 如果不是停止中状态也不是异常状态,则抛出异常
        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) {
            // 设置状态为STOPPED(停止完成)
            setStateInternal(LifecycleState.STOPPED, null, false);
            destroy();
        }
    }
}

5、destroy

  • destroy和stop类似,先做校验后切换状态,具体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);
    }
}

总结

  • 为了统一管理组件的初始化、启动、停止、销毁方法,抽象出生命周期接口Lifecycle
  • 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;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1498674.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaEE之volatile关键字

一.内存可见性问题 什么是内存可见性问题 计算机运行的程序/代码&#xff0c;往往需要访问数据。这些数据往往存在于内存中。 cup使用此变量时&#xff0c;就会把内存中的数据先读出来&#xff0c;加载到cpu寄存器中&#xff0c;再去参与运算。 但是&#xff0c;关键是cpu读…

opengl 学习(三)-----着色器

着色器 分类demo效果解析教程 分类 OPengl C demo #include "glad/glad.h" #include "glfw3.h" #include <iostream> #include <cmath> #include <vector>#include <string> #include <fstream> #include <sstream>…

Spring源码:手写AOP

文章目录 一、概念1、AOP是什么&#xff1f;2、相关概念1&#xff09;目标对象Target2&#xff09;通知Advice3&#xff09;连接点Joinpoint4&#xff09;切点Pointcut5&#xff09;切面Aspect6&#xff09;织入Weaving 二、分析三、实现1、实现Advice1&#xff09;前置通知2&a…

IDEA中新增文件,弹出框提示是否添加到Git点错了,怎么重新设置?

打开一个配置了Git的项目&#xff0c;新增一个文件&#xff0c;会弹出下面这个框。提示是否将新增的文件交给Git管理。 一般来说&#xff0c;会选择ADD&#xff0c;并勾选Dont ask agin&#xff0c;添加并不再询问。如果不小心点错了&#xff0c;可在IDEA中重新设置&#xff08…

经典语义分割(二)医学图像分割模型UNet

经典语义分割(二)医学图像分割模型UNet 我们之前介绍了全卷积神经网络( FCN) &#xff0c;FCN是基于深度学习的语义分割算法的开山之作。 今天我们介绍另一个语义分割的经典模型—UNet&#xff0c;它兼具轻量化与高性能&#xff0c;通常作为语义分割任务的基线测试模型&#x…

海格里斯HEGERLS助力服装业领域数智化转型 配备7000个托盘位 仓库容量增超110%

近年来&#xff0c;用工荒成为服装制造行业的一大痛点。对此&#xff0c;整个生产体系就要不断地向智能化、自动化生产设备进行转型&#xff0c;甚至在研发设计上都要面向自动化做一些新一代服装制造业的开发。 作为较早入局物流赛道的河北沃克&#xff0c;目前已构建起以AI赋能…

P2241 统计方形(数据加强版) python解法

求n*m网格内矩形的数目 - tenos - 博客园 (cnblogs.com) 法一&#xff08;题解推规律暴力枚举得到&#xff09;&#xff1a; n,mmap(int,input().split()) sqr,rec0,0 #正方形和长方形个数 #以长宽做循环&#xff0c;每次求n*m大小的矩形的个数 #题解是从0开始的&#xff0c;我…

Java二级--操作题详解(1)

目录 1.第一套&#xff1a; 1.1 基本操作&#xff1a; 1.2 题解分析&#xff1a; 2.1 简单应用&#xff1a; 2.2 解题分析&#xff1a; 3.1 综合应用&#xff1a; 3.2解题分析&#xff1a; 1.第一套&#xff1a; 1.1 基本操作&#xff1a; 在考生文件夹中存有文件名为J…

浅析扩散模型与图像生成【应用篇】(八)——BBDM

8. BBDM: Image-to-Image Translation with Brownian Bridge Diffusion Models 本文提出一种基于布朗桥&#xff08;Brownian Bridge&#xff09;的扩散模型用于图像到图像的转换。图像到图像转换的目标是将源域 A A A中的图像 I A I_A IA​&#xff0c;映射到目标域 B B B中得…

【重要!!退税!退税!】一年一度个人所得税综合年度汇算开始了!

目录标题 如何退税&#xff1f;2023年度个人所得税综合所得汇算清缴操作指南汇算准备标准申报 退税骗局&#xff1f;1.“您有一笔退税待领取”骗局2.“专业人员帮你多退税”骗局3.“诱导填报虚假个税信息”骗局4.“税务稽查人员联系你”骗局 如何退税&#xff1f; 2023年度个人…

【elementplus】el-image图片预览的显示不全问题(和el-table、el-dialog组合使用时)

问题&#xff1a; 在和el-table、el-dialog组合使用时&#xff0c;el-image图片预览的时候&#xff0c;会可能出现显示不全图片的情况。 解决方法&#xff1a; <el-image-viewer:z-index"3000":teleported"true"/>element文档中有属性&#xff1a;…

【SpringBoot3.x教程03】SpringBoot自动配置详解

前言&#xff1a;什么是自动配置 自动配置的原理 Spring Boot自动配置尝试根据添加到项目中的jar依赖、定义的bean以及各种属性设置来自动配置Spring应用。这是通过EnableAutoConfiguration注解实现的&#xff0c;该注解通常是通过SpringBootApplication注解间接应用的。Spring…

如何实现数据中心布线变更管理?

前言 随着科技的不断发展&#xff0c;数据中心作为企业的核心基础设施之一&#xff0c;承载着大量重要的业务数据。在数据中心运维过程中&#xff0c;变更管理流程变得尤为重要&#xff0c;它是确保数据中心基础设施稳定运行和保障数据安全的关键环节。变更管理的定义是指在维…

阿珊解说Vue中`$route`和`$router`的区别

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

栈和队列OJ题:有效的括号,用栈实现队列,用队列实现栈,设计循环队列(C语言版,图文并茂,超级详细)

目录 前言 1. 有效的括号 &#xff08;1&#xff09;题目及示例 &#xff08;2&#xff09;思路及解法 2.用栈实现队列 &#xff08;1&#xff09;题目及示例 &#xff08;2&#xff09;解析及思路 &#xff08;3&#xff09;各部分代码 2.3.1 数据结构设计和创造队列…

官网:随便搞个?那不如不搞,搞不好就给公司减分了。

官网建设确实需要认真对待&#xff0c;不能随便搞。一个粗制滥造的官网可能会给公司带来负面影响&#xff0c;降低品牌形象和用户体验。以下是一些官网建设的重要原则&#xff1a; 专业性&#xff1a;官网应该展示公司的专业性和专业知识。它应该以专业的设计、内容和功能来展示…

1.4 Word2Vec是如何工作的? Word2Vec与LDA 的区别和联系?

1.4 Word2Vec&#xff1a;词嵌入模型之一 场景描述 谷歌2013年提出的Word2Vec是目前最常用的词嵌入模型之一。 Word2Vec实际是一种浅层的神经网络模型,它有两种网络结构&#xff0c;分别是CBOW(Continues Bag of Words)和Skip-gram。 知识点 Word2Vec,隐狄利克雷模型(LDA),…

nginx部署前端工程替代方案gateway

nginx部署前端工程替代方案gateway 有市场要求部署的前端vue工程不使用nginx中间件。想弄国产替代的东方通之类的&#xff0c;公司没有购买该产品&#xff0c;我参考了网上的一些java网关框架&#xff0c;springcloud组件&#xff1a;gateway实现代替。 注意后台都是用java编…

网络安全-appcms-master

一、环境 gethub上面自己找appcms-master 二、分析一下源码以及闯关思路 首先是有一个函数循环以及函数过滤&#xff0c;我们的post会将我们所传的所有val值去进行一个循环&#xff0c;之后通过htmlspecialchars这个函数进行过滤和转换所以val值不能通过单双引号闭合注入的方…

微信私域运营时如何有效降本增效?

在如今这个以流量为王的时代&#xff0c;成功地将流量转化为商业价值显得尤为重要。许多企业选择将流量转移到微信的私域流量中&#xff0c;以提高转化率和营销效果。 但是由于微信平台的限制&#xff0c;比如一台设备在正常情况下只能登录一个账号&#xff0c;无法实现聚合管理…