zoukankan      html  css  js  c++  java
  • 【高软作业4】:Tomcat 观察者模式解析 之 Lifecycle

    一. 预备

    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 的实现为例,如下:

     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 }
    View Code
    • 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 }
    View Code
    • "你可以执行相应操作了",并不是在 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 }
    View Code
    • 至此,流程:“subject 注册 observer --> subject 状态改变 --> observer 做出相应的反馈 结束,subject.init()方法调用如下图:

    三. 结束

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

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

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

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

  • 相关阅读:
    编译Android系统源码和内核源码
    Ubuntu中的解压缩文件的方式
    将秒数转换为基于00:00的时间
    git sshkeygen Fingerprint cannot be generated解决方法
    git bash下的选择、复制、粘贴
    mac 配置jdk maven
    自定义标签
    垃圾收集器和收集算法
    多线程并发中的同步
    现在有T1、T2、T3三个线程,怎样保证T2在T1执行完后执行,T3在T2执行完后执行?使用Join
  • 原文地址:https://www.cnblogs.com/southday/p/9821500.html
Copyright © 2011-2022 走看看