Tomcat中组件的生命周期管理(三)
本文主要目的是自定义举例分析Catalina
内部生命周期管理的运作方式以及拿内部具体源码来具体分析
假设我们有一台电脑由主机(我们用cpu表示)和显示器构成,那么我们要运用上篇文章学到的内容,来管理整个电脑的启动和关闭,先看我们对类的定义。
在本例中我们对Lifecycle
类进行了部分删减,只保留了关于start
和stop
的相关事件。
-
Lifecycle
public interface Lifecycle { // ----------------------------------------------------- Manifest Constants public 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 Methods public 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; @Override public void addLifecycleListener(LifecycleListener listener) { support.addLifecycleListener(listener); } @Override public LifecycleListener[] findLifecycleListeners() { return support.findLifecycleListeners(); } @Override public void removeLifecycleListener(LifecycleListener listener) { support.removeLifecycleListener(listener); } protected void fireLifecycleEvent(String type, Object data) { support.fireLifecycleEvent(type, data); } protected abstract void startInternal() throws LifecycleException; @Override public 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; @Override public 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 { @Override public void startInternal() throws LifecycleException { System.out.println(super.name + "在启动过程中 负载达到了100%!"); } @Override public void stopInternal() throws LifecycleException { System.out.println(name + "在关闭过程中 负载下降到了1%!"); } public CPU(String name) { super.name = name; } }
电脑组成部件 Monitor定义
-
Monitor
public class Monitor extends LifeCycleBase { @Override public void startInternal() throws LifecycleException { System.out.println(name + "在启动过程中 屏幕 很亮!"); } @Override public 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; @Override public void startInternal() throws LifecycleException { System.out.println(name + "在启动过程中 需要先启动子组件"); if (cpu != null) { ((Lifecycle) cpu).start(); } if (monitor != null) { ((Lifecycle) monitor).start(); } } @Override public 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() {
@Override
public void lifecycleEvent(LifecycleEvent event) {
if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
System.out.println("已经监听到 cpu正在准备启动");
}
}
});
monitor.addLifecycleListener(new LifecycleListener() {
@Override
public 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 Services
synchronized (servicesLock) {
for (int i = 0; i < services.length; i++) {
services[i].start();
}
}
}
可以看到思路非常简单
- 触发某个事件(针对自己内部所有监听器)
- 更改自己组件状态
- 调用子组件的
start()
方法,包括globalNamingResources
和StandardService
。
至于这些子组件什么时候设置到本类中的,读者可以自行发现。
我们可以继续往下再看一点,既然调用了StandardService
的start()
方法,查看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 first
if (container != null) {
synchronized (container) {
container.start();
}
}
synchronized (executors) {
for (Executor executor: executors) {
executor.start();
}
}
// Start our defined Connectors second
synchronized (connectorsLock) {
for (Connector connector: connectors) {
try {
// If it has already failed, don't try and start it
if (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设计者设计的精巧,代码的简洁,简直完美!