【高软作业4】:Tomcat 观察者模式解析 之 Lifecycle
一. 预备
- 如果你是Windows用户,使用Eclipse,并且想自行导入源码进行分析,你可能需要:Eclipse 导入 Tomcat 源码
- 如果你已遗忘 观察者模式,那么你可以通过该文章回顾:设计模式(五)观察者模式
- 如果你已遗忘 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源码地址:
- Apache Tomcat 项目地址:https://github.com/apache/tomcat
- Lifecycle.java:https://github.com/apache/tomcat/blob/trunk/java/org/apache/catalina/Lifecycle.java
- LifecycleBase.java:https://github.com/apache/tomcat/blob/trunk/java/org/apache/catalina/util/LifecycleBase.java
- LifecycleListener.java:https://github.com/apache/tomcat/blob/trunk/java/org/apache/catalina/LifecycleListener.java
- UserConfig.java:https://github.com/apache/tomcat/blob/trunk/java/org/apache/catalina/startup/UserConfig.java
- LifecycleState.java:https://github.com/apache/tomcat/blob/trunk/java/org/apache/catalina/LifecycleState.java
- LifecycleEvent.java:https://github.com/apache/tomcat/blob/trunk/java/org/apache/catalina/LifecycleEvent.java
转载请说明出处!have a good time :D
【高软作业4】:Tomcat 观察者模式解析 之 Lifecycle的更多相关文章
- 【高软作业2】:Java IDE调研分析
一 序言 随着软件项目开发需求的增多,拥有一款优秀的.顺手的IDE(Integrated Development Environment)对程序员来说显得格外重要.本文就Java程序开发,选择了3款I ...
- 【高软作业3】:原型化系统 DevTools
原型化系统:DevTools 密码:lcx 1. 这是一个什么样的平台? DevTools,可译为:开发者工具库.初衷是聚集各类开发工具,方便开发者获取:此外,大家可以分享自己的工具库与工 ...
- tomcat原理解析(一):一个简单的实现
tomcat原理解析(一):一个简单的实现 https://blog.csdn.net/qiangcai/article/details/60583330 2017年03月07日 09:54:27 逆 ...
- Tomcat源代码解析系列
学web也有一段时间了.为了从底层了解web应用在Tomcat中的执行,决定看一下Tomcat的源代码參见<How Tomcat works> 和大牛博客.对大体架构有了一定的了解, ...
- Tomcat服务器解析“GET /JavaWebDemo1/1.jsp HTTP/1.1”
(2)服务器收到http请求报文,返回http响应报文 Tomcat服务器解析“GET /JavaWebDemo1/1.jsp HTTP/1.1” Tomcat服务器解析“GET /JavaWebDe ...
- Tomcat请求处理过程(Tomcat源代码解析五)
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/ ...
- Tomcat架构解析(二)-----Connector、Tomcat启动过程以及Server的创建过程
Connector用于跟客户端建立连接,获取客户端的Socket,交由Container处理.需要解决的问题有监听.协议以及处理器映射等等. 一.Connector设计 Connector要实现的 ...
- Tomcat架构解析(三)-----Engine、host、context解析以及web应用加载
上一篇博文介绍了Server的创建,在Server创建完之后,就进入到Engine的创建过程,如下: 一.Engine的创建 1.创建Engine实例 当前次栈顶元素为Service对象,通过Se ...
- Tomcat架构解析(一)-----Tomcat总体架构
Tomcat是非常常用的应用服务器,了解Tomcat的总体架构以及实现细节,对于理解整个java web也是有非常大的帮助. 一.Server 1.最简单的服务器结构 最简单的服务器结构如图所示: ...
随机推荐
- yaml服务部署示例
apiVersion: apps/v1kind: Deploymentmetadata: name: igirl namespace: chaolai labels: app: igirl ...
- python搭建后台服务
后端 # coding:utf-8 # 2019/10/22 16:01 # huihui # ref: from flask import Flask, abort, request, jsonif ...
- iOS 开发中常用的排序(冒泡、选择、快速、插入、希尔、归并、基数)算法
1.冒泡排序: 冒泡算法是一种基础的排序算法,这种算法会重复的比较数组中相邻的两个元素.如果一个元素比另一个元素大(小),那么就交换这两个元素的位置.重复这一比较直至最后一个元素.这一比较会重复n-1 ...
- Hosts工作原理及作用
Hosts是一个没有扩展名的系统文件,可以用记事本等工具打开.其作用就是将一些常用的网址域名与其对应的IP地址建立一个关联“数据库”.当用户在浏览器中输入一个需要登录的网址时,系统会先检查系自己的Ho ...
- 1.ORM介绍,基本配置及通过ORM框架创建表
1.介绍 ORM全拼Object-Relation Mapping(对象-关系映射) 作用:主要实现模型对象到关系数据库数据的映射 通过ORM框架作为一个中间者或者是一个桥梁,开发者通过定义模型类,属 ...
- Sonic_cli常用命令
用户名:admin 密码:YourPaSsWoRd //change password1>admin@sonic:~$ passwdChanging password for admin.(cu ...
- [转]使用Struts 2防止表单重复提交
转自 用户重复提交表单在某些场合将会造成非常严重的后果.例如,在使用信用卡进行在线支付的时候,如果服务器的响应速度太慢,用户有可能会多次点击提交按钮,而这可能导致那张信用卡上的金额被消费了多次.因此, ...
- 二十一 Struts的数据校验两种方式:手动编码和xml校验
数据的校验: 一.前台校验:JS校验 JS的校验不是必须的,JS可以被绕行,可以提升用户体验 二.后台校验:编码校验 必须的校验 三.校验的方式: 手动编码(不建议使用) 配置文件(支持) 手动编码的 ...
- 吴裕雄--天生自然ORACLE数据库学习笔记:Oracle 11g的闪回技术
alter system set db_recovery_file_dest_size=4g scope=both; connect system/1qaz2wsx as sysdba; archiv ...
- 李德胜系列——李德胜和CPC人的初心
很久很久以前,有三条恶龙盘踞着村庄,恶龙们及其爪牙对村民敲骨吸髓,逼着村民卖儿鬻女.苦不堪言.但是村民们却对此压迫习以为常,逆来顺受. 后来,一个书生来到了这个村庄,告诉村民,不许跪,也没有人值得他们 ...