Tomcat中组件的生命周期管理(三)

本文主要目的是自定义举例分析Catalina内部生命周期管理的运作方式以及拿内部具体源码来具体分析

假设我们有一台电脑由主机(我们用cpu表示)和显示器构成,那么我们要运用上篇文章学到的内容,来管理整个电脑的启动和关闭,先看我们对类的定义。

在本例中我们对Lifecycle类进行了部分删减,只保留了关于startstop的相关事件。

  • Lifecycle

      public interface Lifecycle {// ----------------------------------------------------- Manifest Constantspublic static final String START_EVENT = "start";/*** The LifecycleEvent type for the "component before start" event.*/public static final String BEFORE_START_EVENT = "before_start";/*** The LifecycleEvent type for the "component after start" event.*/public static final String AFTER_START_EVENT = "after_start";/*** The LifecycleEvent type for the "component stop" event.*/public static final String STOP_EVENT = "stop";/*** The LifecycleEvent type for the "component before stop" event.*/public static final String BEFORE_STOP_EVENT = "before_stop";/*** The LifecycleEvent type for the "component after stop" event.*/public static final String AFTER_STOP_EVENT = "after_stop";// --------------------------------------------------------- Public Methodspublic void addLifecycleListener(LifecycleListener listener);public LifecycleListener[] findLifecycleListeners();public void removeLifecycleListener(LifecycleListener listener);public void start() throws LifecycleException;public void stop() throws LifecycleException;}

同样LifecycleBase类也只保留了start,stop相关方法。

  • LifecycleBase

      public abstract class LifeCycleBase implements Lifecycle {private LifecycleSupport support = new LifecycleSupport(this);//组件名称public String name;@Overridepublic void addLifecycleListener(LifecycleListener listener) {support.addLifecycleListener(listener);}@Overridepublic LifecycleListener[] findLifecycleListeners() {return support.findLifecycleListeners();}@Overridepublic void removeLifecycleListener(LifecycleListener listener) {support.removeLifecycleListener(listener);}protected void fireLifecycleEvent(String type, Object data) {support.fireLifecycleEvent(type, data);}protected abstract void startInternal() throws LifecycleException;@Overridepublic void start() throws LifecycleException {System.out.println(name + " 准备启动");fireLifecycleEvent(Lifecycle.BEFORE_START_EVENT, null);System.out.println(name + " 正在启动");fireLifecycleEvent(Lifecycle.START_EVENT, null);startInternal();System.out.println(name + " 启动完毕");fireLifecycleEvent(Lifecycle.AFTER_START_EVENT, null);}protected abstract void stopInternal() throws LifecycleException;@Overridepublic void stop() throws LifecycleException {System.out.println(name + " 准备关闭");fireLifecycleEvent(Lifecycle.BEFORE_STOP_EVENT, null);System.out.println(name + " 正在关闭");stopInternal();fireLifecycleEvent(Lifecycle.STOP_EVENT, null);System.out.println(name + " 关闭完毕");fireLifecycleEvent(Lifecycle.AFTER_STOP_EVENT, null);}}

电脑组成部件 CPU定义

  • CPU

      public class CPU extends LifeCycleBase {@Overridepublic void startInternal() throws LifecycleException {System.out.println(super.name + "在启动过程中 负载达到了100%!");}@Overridepublic void stopInternal() throws LifecycleException {System.out.println(name + "在关闭过程中 负载下降到了1%!");}public CPU(String name) {super.name = name;}}

电脑组成部件 Monitor定义

  • Monitor

      public class Monitor extends LifeCycleBase {@Overridepublic void startInternal() throws LifecycleException {System.out.println(name + "在启动过程中 屏幕 很亮!");}@Overridepublic void stopInternal() throws LifecycleException {System.out.println(name + "在关闭过程中 屏幕渐渐暗了下去");}public Monitor(String name) {super.name = name;}}

电脑类的定义

  • Computer

      public class Computer extends LifeCycleBase {private CPU cpu ;private Monitor monitor;@Overridepublic void startInternal() throws LifecycleException {System.out.println(name + "在启动过程中 需要先启动子组件");if (cpu != null) {((Lifecycle) cpu).start();}if (monitor != null) {((Lifecycle) monitor).start();}}@Overridepublic void stopInternal() throws LifecycleException {System.out.println(name + "在关闭过程中  需要先关闭子组件");if (cpu != null) {((Lifecycle) cpu).stop();}if (monitor != null) {((Lifecycle) monitor).stop();}}public Computer(String name) {super.name = name;}public void setCpu(CPU cpu) {this.cpu = cpu;}public void setMonitor(Monitor monitor) {this.monitor = monitor;}}

运行类代码

public class MainClass {public static void main(String[] args) throws Exception {Computer computer = new Computer("电脑");CPU cpu = new CPU("CPU");Monitor monitor = new Monitor("显示器");computer.setCpu(cpu);computer.setMonitor(monitor);cpu.addLifecycleListener(new LifecycleListener() {@Overridepublic void lifecycleEvent(LifecycleEvent event) {if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {System.out.println("已经监听到 cpu正在准备启动");}}});monitor.addLifecycleListener(new LifecycleListener() {@Overridepublic void lifecycleEvent(LifecycleEvent event) {if (event.getType().equals(Lifecycle.AFTER_STOP_EVENT)) {System.out.println("已经监听到显示器 已经停止");}}});//启动computer.start();System.out.println("------------------------------------------");computer.stop();}}

运行结果

电脑 准备启动
电脑 正在启动
电脑在启动过程中 需要先启动子组件
CPU 准备启动
已经监听到 cpu正在准备启动
CPU 正在启动
CPU在启动过程中 负载达到了100%!
CPU 启动完毕
显示器 准备启动
显示器 正在启动
显示器在启动过程中 屏幕 很亮!
显示器 启动完毕
电脑 启动完毕
------------------------------------------
电脑 准备关闭
电脑 正在关闭
电脑在关闭过程中  需要先关闭子组件
CPU 准备关闭
CPU 正在关闭
CPU在关闭过程中 负载下降到了1%!
CPU 关闭完毕
显示器 准备关闭
显示器 正在关闭
显示器在关闭过程中 屏幕渐渐暗了下去
显示器 关闭完毕
已经监听到显示器 已经停止
电脑 关闭完毕

从源码可以看到每个组件的启动都会调用父类的start()方法,而start()方法又会调用本类的startInternal()方法,stop方法类似。在父类的start()方法定义了一些组件共性的动作,而在startInternal()方法中定义了组件自己的特殊动作。并且每个组件都可以自行添加自己的监听器。从运行的代码可以看到,只要设置好每个组件的关系就可以统一管理每个组件的启动关闭了。Catalina中的生命周期管理的模式大概就是这样,下面我们找个具体的类来分析。

我们主要分析start()方法相关,其他类似init(),stop(),destroy()方法都是类似的。我们从前面的文章可以知道Tomcat启动的时候是调用了Bootstrap类的main()方法,而main()方法中最后调用了Catalina类的start()方法,我们查看Catalina类的start()方法,其中

getServer().start();

这一步又调用了StandardServer类的start()方法,从这里就Catalina是最顶层组件,下面所有的组件都开始需要进行生命周期管理了。所以查看StandardServer类的定义

public final class StandardServer extends LifecycleMBeanBase implements Server

再查看LifecycleMBeanBase类的定义

public abstract class LifecycleMBeanBase extends LifecycleBase implements MBeanRegistration

我们在这里就看到了上文介绍的关键类LifecycleBase类。之所以有个LifecycleMBeanBase类横跨在这里主要是因为Tomcat要将组件纳入JMX管理,所以用这个类来实现,这个不再本文的讲解范围之内,所以暂时不讨论,可以当作组件直接继承LifecycleBase类。

既然StandardServer类直接继承了LifecycleBase类,那么Catalina调用StandardServer类的start()方法就是调用LifecycleBase类的start()方法(这样的前提是StandardServer,LifecycleMBeanBase类中没有start()方法,实际上这2个类的确没有实现start()方法)。上篇文章已经分析过LifecycleBase类的start()方法具体源码,因为start()方法中会调用子类的startInternal()方法,所以可以直接查看StandardServer类的startInternal()方法。

@Override
protected void startInternal() throws LifecycleException {fireLifecycleEvent(CONFIGURE_START_EVENT, null);setState(LifecycleState.STARTING);globalNamingResources.start();// Start our defined Servicessynchronized (servicesLock) {for (int i = 0; i < services.length; i++) {services[i].start();}}
}

可以看到思路非常简单

  • 触发某个事件(针对自己内部所有监听器)
  • 更改自己组件状态
  • 调用子组件的start()方法,包括globalNamingResourcesStandardService

至于这些子组件什么时候设置到本类中的,读者可以自行发现。

我们可以继续往下再看一点,既然调用了StandardServicestart()方法,查看StandardService类的定义。

public class StandardService extends LifecycleMBeanBase implements Service

类似StandardServer,那么直接查看其startInternal()方法。

    @Override
protected void startInternal() throws LifecycleException {if(log.isInfoEnabled())log.info(sm.getString("standardService.start.name", this.name));setState(LifecycleState.STARTING);// Start our defined Container firstif (container != null) {synchronized (container) {container.start();}}synchronized (executors) {for (Executor executor: executors) {executor.start();}}// Start our defined Connectors secondsynchronized (connectorsLock) {for (Connector connector: connectors) {try {// If it has already failed, don't try and start itif (connector.getState() != LifecycleState.FAILED) {connector.start();}} catch (Exception e) {log.error(sm.getString("standardService.connector.startFailed",connector), e);}}}
}

虽然代码看起来很多,但是按照上面的思路来看的话,还是那几步。

  • 更改当前组件状态
  • 调用自己子组件的start()方法包含container,connector

看到这里我们就不继续往下看了,因为之前启动的文章都已经分析过了,是不是觉得看到这里对启动的流程理解又上了一层。其实自己看看每个组件的startInternal()方法都是在启动自己的子组件,而组件的子组件可以从哪里找到呢?可以看看Digster那篇文章,疑惑看看server.xml也许会有恍然大悟的感觉,至于具体代码去哪里找,读者可以自行挖掘。

写到这里只能感慨Tomcat设计者设计的精巧,代码的简洁,简直完美!

转载于:https://www.cnblogs.com/coldridgeValley/p/5816417.html

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

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

相关文章

Python rang()函数

返回类型为迭代器 r range(11) print(r) 若输出r中的值&#xff0c;需要调用list(r) print(list(r)) 输出&#xff1a; 方法二: #二&#xff1a; r1 range(1,10) print(list(r1)) 方法三&#xff1a; #三&#xff1a; r2 range(1,10,2) print(list(r2)) 判断某一个数是…

Python 中的 while循环 和 for... in ...循环

for item in Python:print(item, end) print()for item in range(10):print(item, end)# 当不需要自定义变量时候&#xff0c;可以用”_“代替 for _ in range(5) :print(hello world)# 计算累加和 sum 0 for i in range(1,101) :if i%20 :sum i print(sum) While: a 0 while…

css笔记——css 实现自定义按钮

css实现自定义按钮的样式实际上很早就有了&#xff0c;只是会用的人不是很多&#xff0c;里面涉及到了最基础的css写法&#xff0c;在火狐中按钮还是会显示出来&#xff0c;这时需要将i标签的背景设置为白色&#xff0c;同时z-index设置比input高一些&#xff0c;这样才可以把按…

Hibernate中主键生成策略

主键生成策略 increment identity sequence native uuid assigned 1) increment 由hibernate完成 主键递增&#xff0c; 原理&#xff1a;select max(id) , insert时max(id)1 &#xff0c;完成主键递增 优点&#xff1a;跨数据库 缺点&#xff1a;多线程并发访问问题&#xff0…

Python四大金刚之一:列表

前言 列表中可以存储多个数据类型不同的对象 一个对象的内存空间&#xff1a; 因此一个列表的内存空间为: a 10 lst [hello , a , a ,world] print(lst) print(type(lst)) print(id(lst))print(lst[0] type: , type(lst[0])) 一、列表的创建&#xff1a; 内存示意图: #创建…

牛客网未通过代码---

请实现一个算法&#xff0c;在不使用额外数据结构和储存空间的情况下&#xff0c;翻转一个给定的字符串(可以使用单个过程变量)。 给定一个string iniString&#xff0c;请返回一个string&#xff0c;为翻转后的字符串。保证字符串的长度小于等于5000。 string reverse(string …

Python四大金刚之二:字典

引言 列表、字典&#xff1a;可变序列&#xff0c;可以执行增删改排序等 字典&#xff1a;无序的 一、字典的创建 #使用{}创建 scores {张三:100 ,李四:98 ,王麻子:72} print(scores) print(type(scores))#使用内置函数dict() student dict(name jack , age 16) print(st…

Java 加密 base64 encode

版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主允许不得转载。 【前言】 计算机中的数据都是二进制的&#xff0c;不管是字符串还是文件&#xff0c;而加密后的也是二进制的&#xff0c; 而我们要看到的往往是字符串&#xff0c;本文就介绍了将byte[]转为各种进制…

Python四大金刚之三:元组

引言 一、元组的创建方式 #第一种: t (python,No.1) print(t) print(type(t)) #第二种: 内置函数tuple() t1 tuple((python,No.2)) print(t1) print(type(t1))注&#xff1a;当元组中只有一个元素时候&#xff0c;需要加 逗号&#xff01;&#xff01;&#xff01;&#xff…

snapshot---caffemodel和solverstate

生成的caffemodel文件去做分类&#xff0c;solverstate是用来中断训练后重新开始的状态文件。RestoreSolverState&#xff08;&#xff09;可以用来读取solverstate存储的训练状态&#xff0c;继续训练~但是感觉solverstate除了可以在断电、服务器跪的情况&#xff0c;别的好像…

Python四大金刚之四:集合

引言 一、集合的创建方式 #使用{} s {1,2,3,4,3,2} #不允许重复元素 print(s)#使用内置函数set() s set(range(6)) print(s) print(set(range(9))) print(set([10,12,13,4])) print(set(Python)) 二、集合的相关操作 set {10,20,30,40,50} print(10 in set) #新增操作 #add…

Swift-属性监听

监听属性的改变(开发中使用很多) oc中长是重写set方法 swift通过属性监听器 class Dog: NSObject {var name:String?{ // 属性监听器 // 属性即将改变监听willSet{ // print("111") // print(name)print(newValue)} // …

Python-学习-import语句导入模块

简单的学习一下调用外部的模块文件。 在Python中&#xff0c;模块是一种组织形式&#xff0c;它将彼此有关系的Pyrhon 代码组织到一个个独立的文件当中&#xff0c;模块可以包含可执行代码&#xff0c;函数&#xff0c;和类或者是这些东西的组合。 当我们创建一个Python 源文件…

Android Studio Gradle构建脚本

Gradle是一种依赖管理工具&#xff0c;基于Groovy语言&#xff0c;面向Java应用为主&#xff0c;它抛弃了基于XML的各种繁琐配置&#xff0c;取而代之的是一种基于Groovy的内部领域特定&#xff08;DSL&#xff09;语言。 构建工具就是对你的项目进行编译&#xff0c;运行&…

深度学习中用到的一些函数

1.np.poly1d() 通过np.ploy1d(p[1,1]) 会返回一个 f(x) 1x1 2.np.random.normal() 3.np.random.rand() 4.np.linspace() 得到等差数列 numpy.linspace(start, stop, num50, endpointTrue, retstepFalse, dtypeNone, axis0) Return evenly spaced numbers over a specified i…

Django Python MySQL Linux 开发环境搭建

Django Python MySQL Linux 开发环境搭建 1、安装Python 进行Python开发&#xff0c;首先必须安装python&#xff0c;对于linux 或者Mac 用户&#xff0c;python已经预装。 在命令行输入python&#xff0c;如果出现一些关于版本等等的信息&#xff0c;则python已经预装。 没有的…

sklearn中的make_blobs的用法

sklearn中的make_blobs函数主要是为了生成数据集的&#xff0c;具体如下 data_set, label make_blobs(n_features3,n_samples50, centers3, random_state0, cluster_std0.1)