【高软作业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 的实现为例,如下:
1 @Override 2 public final synchronized void init() throws LifecycleException { 3 if (!state.equals(LifecycleState.NEW)) { 4 invalidTransition(Lifecycle.BEFORE_INIT_EVENT); 5 } 6 7 try { 8 setStateInternal(LifecycleState.INITIALIZING, null, false); 9 initInternal(); 10 setStateInternal(LifecycleState.INITIALIZED, null, false); 11 } catch (Throwable t) { 12 handleSubClassException(t, "lifecycleBase.initFail", toString()); 13 } 14 }
- 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) 内部是如何实现的吧(主要看最后面几行),源码如下:
1 private synchronized void setStateInternal(LifecycleState state, Object data, boolean check) 2 throws LifecycleException { 3 if (log.isDebugEnabled()) { 4 log.debug(sm.getString("lifecycleBase.setState", this, state)); 5 } 6 7 if (check) { 8 // Must have been triggered by one of the abstract methods (assume 9 // code in this class is correct) 10 // null is never a valid state 11 if (state == null) { 12 invalidTransition("null"); 13 // Unreachable code - here to stop eclipse complaining about 14 // a possible NPE further down the method 15 return; 16 } 17 18 // Any method can transition to failed 19 // startInternal() permits STARTING_PREP to STARTING 20 // stopInternal() permits STOPPING_PREP to STOPPING and FAILED to 21 // STOPPING 22 if (!(state == LifecycleState.FAILED || 23 (this.state == LifecycleState.STARTING_PREP && 24 state == LifecycleState.STARTING) || 25 (this.state == LifecycleState.STOPPING_PREP && 26 state == LifecycleState.STOPPING) || 27 (this.state == LifecycleState.FAILED && 28 state == LifecycleState.STOPPING))) { 29 // No other transition permitted 30 invalidTransition(state.name()); 31 } 32 } 33 34 this.state = state; 35 String lifecycleEvent = state.getLifecycleEvent(); 36 if (lifecycleEvent != null) { 37 fireLifecycleEvent(lifecycleEvent, data); 38 } 39 }
- "你可以执行相应操作了",并不是在 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) 内部实现,源码如下:
1 // LifecycleBase.java 2 /** 3 * Allow sub classes to fire {@link Lifecycle} events. 4 * 5 * @param type Event type 6 * @param data Data associated with event. 7 */ 8 protected void fireLifecycleEvent(String type, Object data) { 9 LifecycleEvent event = new LifecycleEvent(this, type, data); 10 for (LifecycleListener listener : lifecycleListeners) { 11 listener.lifecycleEvent(event); 12 } 13 } 14 15 // UserConfig.java 16 /** 17 * Process the START event for an associated Host. 18 * 19 * @param event The lifecycle event that has occurred 20 */ 21 @Override 22 public void lifecycleEvent(LifecycleEvent event) { 23 24 // Identify the host we are associated with 25 try { 26 host = (Host) event.getLifecycle(); 27 } catch (ClassCastException e) { 28 log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e); 29 return; 30 } 31 32 // Process the event that has occurred 33 if (event.getType().equals(Lifecycle.START_EVENT)) 34 start(); 35 else if (event.getType().equals(Lifecycle.STOP_EVENT)) 36 stop(); 37 }
- 至此,流程:“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