一. 预备

  1. 如果你是Windows用户,使用Eclipse,并且想自行导入源码进行分析,你可能需要:Eclipse 导入 Tomcat 源码
  2. 如果你已遗忘 观察者模式,那么你可以通过该文章回顾:设计模式(五)观察者模式
  3. 如果你已遗忘 UML类图相关知识,那么你可以通过文章 (五分钟读懂UML类图 )快速回顾

二. 启程

1. Tomcat组件生命周期

Tomcat中包含多种组件,每个组件有各自的生命周期,而每个生命周期中又包含多种状态,这些状态会根据程序的运行而相互转换,在这个过程中,某些组件会随之做出相应的反馈。

下面是Tomcat组件生命周期状态转换图,来自tomcat源码Lifecycle.java的注释:https://github.com/apache/tomcat/blob/trunk/java/org/apache/catalina/Lifecycle.java

2. Lifecycle中的观察者模式

生命周期的状态改变,某些组件会随之做出相应的反馈,该运作模式符合观察者模式的应用范围。下面是Tomcat中关于Lifecycle的观察者模式类图:

(为了描述方便,我对类的成员进行简化,只给出文章讲解会用到的成员;如果图片看不清,鼠标右键->查看图像,Firefox是这样的)

 3. 实现原理

我们通过 init() 方法的运行过程来看 Lifecycle 观察者模式的实现原理。

  • Lifecycle subject; // 生命周期(主题)
  • LifecycleListener observer; // 观察者
  • subject.addLifecycleListener(observer); // 主题将观察者添加到观察者列表(观察者注册)
  • subject.init(); // 生命周期状态 NEW ----> INITIALIZED

在 生命周期状态 由 NEW 转到 INITIALIZED 的过程中,subject 会以 LifecycleEvent 为媒介来通知 observer,说:“我的状态已经改变,你可以执行相关的操作了”,以 LifecycleBase 的实现为例,如下:

 @Override
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());
}
}
  • subject.init()

    • setStateInternal(LifecycleState.INITIALIZING, null, false); // 设置当前状态为 INITIALIZING,并通知 observer,说:“我现在的状态变成了 INITIALIZING,你可以执行相应操作了”
    • initInternal(); // 内部初始化(模版方法)
    • setStateInternal(LifecycleState.INITIALIZED, null, false); // 设置当前状态为 INITIALIZED,并通知 observer,说:“我现在状态改为 INITIALIZED,你可以执行相应操作了”

来看 LifecycleBase 中的 setStateInternal(LifecycleState state, Object data, boolean check) 内部是如何实现的吧(主要看最后面几行),源码如下:

 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);
}
}
  • "你可以执行相应操作了",并不是在 observer 端执行操作,而是 subject 通过 observer 提供的接口 lifecycleEvent(LifecycleEvent event) 来执行操作
  • subject 通过调用其内部方法 fireLifecycleEvent(String type, Object data) (会被setStateInternal(...)方法调用)使其观察者的方法 lifecycleEvent(LifecycleEvent event) 得到执行,从而达到消息专递的目的

以下是 LifecycleBase 中的 fireLifecycleEvent(String type, Object data)  的内部实现,以及 UserConfig 中的 lifecycleEvent(LifecycleEvent event) 内部实现,源码如下:

 // LifecycleBase.java
/**
* Allow sub classes to fire {@link Lifecycle} events.
*
* @param type Event type
* @param data Data associated with event.
*/
protected void fireLifecycleEvent(String type, Object data) {
LifecycleEvent event = new LifecycleEvent(this, type, data);
for (LifecycleListener listener : lifecycleListeners) {
listener.lifecycleEvent(event);
}
} // UserConfig.java
/**
* Process the START event for an associated Host.
*
* @param event The lifecycle event that has occurred
*/
@Override
public void lifecycleEvent(LifecycleEvent event) { // Identify the host we are associated with
try {
host = (Host) event.getLifecycle();
} catch (ClassCastException e) {
log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e);
return;
} // Process the event that has occurred
if (event.getType().equals(Lifecycle.START_EVENT))
start();
else if (event.getType().equals(Lifecycle.STOP_EVENT))
stop();
}
  • 至此,流程:“subject 注册 observer --> subject 状态改变 --> observer 做出相应的反馈” 结束,subject.init()方法调用如下图:

三. 结束

观察者模式给 Tomcat 生命周期管理带来的好处:

  • 解除 生命周期 与 依赖生命周期组件 的耦合,让双方都依赖于各自的抽象,使得各自内部实现的变化不会影响到另一方
  • 通过接口调用,增加了程序设计的灵活性和可扩展性,双方都可根据需要来扩展自己的子类,只要该子类按要求实现了相关接口方法就行
  • 支持一对多的 消息专递 / 事件响应,即:某个事物的状态改变,会使依赖该事物的其他多个事物 收到消息 / 做出反馈

本文所涉及的Java源码地址:

转载请说明出处!have a good time :D

最新文章

  1. ios图文混排
  2. C语言的数据、常量和变量
  3. python模块使用案例
  4. 设置html的div中背景图片长宽
  5. Linux 添加环境变量和删除环境变量
  6. uniquery 在win2008 下hold的问题。
  7. 【转载】运维小技巧:使用ss命令代替 netstat
  8. PHP 中const 与define 区别
  9. Ansible详解(二)
  10. POJ 1251 Jungle Roads(最小生成树)
  11. 芝麻HTTP:Ajax结果提取
  12. 46个Linux面试常见问题送给你
  13. :before添加图片,IE8兼容
  14. PHP错误代号列表
  15. python爬虫慕课基础2
  16. css学习_css清除浮动
  17. /var/run/utmp文件操作函数
  18. Spark Strcutured Streaming中使用Dataset的groupBy agg 与 join 示例(java api)
  19. 新版jquery的ajax调用 , jquery1.5以上
  20. 仿淘宝头像上传功能(三)——兼容 IE6 浏览器。

热门文章

  1. Redis注意点记录
  2. Cisco AP-Regulatory Domain
  3. 整个DIV 块垂直居中
  4. 【转载】Eclipse 最常用快捷键 (动画讲解),最简单的一些快捷键
  5. Java中几种office文档转pdf的方式
  6. lc 0226
  7. 【LOJ3087】「GXOI / GZOI2019」旅行者
  8. 八 Spring的IOC的XML和注解的区别及其整合开发
  9. 汇编语言从入门到精通-5微机CPU的指令系统1
  10. linux用户权限、系统信息相关命令(待学)