tomcat源码解读二 tomcat的生命周期

1    生命周期

1.1    观察者模型

tomcat生命周期采用了观察者模式,所以在介绍生命周期的时候不得不介绍观察者模式

观察者模式定义了对象间的一种一对多依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新

观察者模式:

  根据UML图可以看出所有被观察的对象Observer的实现类(可以有多个具体实现类)被添加到观察者Subject的实现类SubjectImpl中的observerList集合中去,这样SubjectImpl对象可以通过遍历observerList中对象并调用其方法实现对所有观察对象的改变,subject这个句柄也存在与Observer的实现类中,所以当某个观察对象改变了就可以直接改变所有观察对象的信息。这就是简单的观察者模式的实现原理,现在我们来看一下tomcat生命周期是如何使用观察者的

1.2    生命周期时序图

这里只展示唤醒的时序图,添加一般是在解析标签实例化通过在规则begin中添加

1.3    生命周期源码解读

由于生命周期采用的是观察者,所以我将以观察者模式的角度来解读,下面首先展示一张以standHost HostConfig举例的观察者模式的类图

   生命周期中与观察者相对应的类

  LifecycleSupport   对应的观察者接口

   LifecycleBase      对应的是观察者的实例但是其是一个抽象类,具体实现是StandardHost等

   LifecycleListener   对应的观察对象接口

  HostConfig        对应的观察对象的实现

1.3.1  添加监听器

tomcat的架构设计是以组件的方式进行加载启动,所以很多东西具有共用型,在其中有很多观察者模式如在StandardContext和ContextConfig中standardContext是观察者,在StandardHost和HostConfig中HostConfig是一个观察者,按照观察者模式这个类应该直接实现Lifecycle进行实现,但是他们有存在一些共有的方法实现如添加监听器,并且声明周期不仅仅是简单的唤醒,它存在多种状态,根据这些状态在唤醒观察对象的时候会根据其状态不同会调用不同的方法。而这些实现逻辑是相同的,所以将其提出来让所有观察者继承,但是调用各组件具体功能方法是不同的所以将其抽象化,所以不能被直接实例化.最红形成抽象类LifecycleBase

部分代码如下:

public abstract class LifecycleBase implements Lifecycle {
    private final LifecycleSupportlifecycle = new LifecycleSupport(this);
/**添加监听器*/
 @Override
 public void addLifecycleListener(LifecycleListenerlistener){
     lifecycle.addLifecycleListener(listener);
 }
}

这就是一个添加监听器的方法(对应与观察者模式中的添加观察对象),至于如何将观察对象添加到观察者中去,下面以StandardHost为例。

根据digester构建规则然后在解析server.xml文件的时候根据Host标签解析对应的StandardHost实例,并给其添加规则LifecycleListenerRule,这个规则的作用就是StandardHost是实例化后会调用addLifecycleListenerHostConfig实例添加到其LifecycleSupport句柄,具体代码执行如下:

HostRuleSet.java

digester.addObjectCreate(prefix + "Host",
                         "org.apache.catalina.core.StandardHost",
                         "className");
digester.addSetProperties(prefix + "Host");
digester.addRule(prefix + "Host",
                 new CopyParentClassLoaderRule());
digester.addRule(prefix + "Host",
                 new LifecycleListenerRule
                 ("org.apache.catalina.startup.HostConfig",
                  "hostConfigClass"));
digester.addSetNext(prefix + "Host",
                    "addChild",
                    "org.apache.catalina.Container");
   
 
 
/**
 * 这个解析规则的主要目的是将监听器添加到对应的实例
 * StandardEngine ==> EngineConfig
 * StandardHost   ==> HostConfig
 * 针对StandardHost来进行分析
 * */
 @Override
 public void begin(Stringnamespace, String name, Attributes attributes)
     throws Exception {
     //获取元素
     Container c =(Container) digester.peek();
     Container p = null;
     //获取栈底元素如果继承Container赋给p 这里是StandardEngine由于其继承Container 所以p为StandardEngine
     //这一步作用只是为了后面看能否从其实例中获取configClass,一般都为空
     Object obj = digester.peek(1);
     if (obj instanceof Container) {
         p = (Container) obj;
     }

     String className = null;
     //检查是否有特定的属性名如果有从标签中获取这个元素为hostConfigClass
     if (attributeName!= null) {
         String value =attributes.getValue(attributeName);
         if (value != null)
             className = value;
     }

     // 在p这个实例调用getHostConfigClass方法获取className值如果存在会覆盖上面的值
     if (p != null &&className == null) {
         String configClass = (String)IntrospectionUtils.getProperty(p, attributeName);
         if (configClass!= null && configClass.length() > 0) {
             className = configClass;
         }
     }
     //如果className为空则使用默认的,即构建实例传入的
     if (className ==null) {
         className = listenerClass;
     }
     //实例化这个监听器即观察对象的实例
     Class<?> clazz =Class.forName(className);
     LifecycleListener listener =(LifecycleListener) clazz.newInstance();
     //添加监听器到对应的组件 hostConfig则是添加到StandardHost
     c.addLifecycleListener(listener);
 }

1.3.2  唤醒监听器

所谓唤醒观察对象就是触发所有其观察者方法,针对于生命周期就是当某个组件调用fireLifecycleEvent方法的时候根据当前组件所处于的状态来触发相应的事件,还是以StandardHost和HostConfig来进行演示。

   ①在组件初始化前后都设置了一下当前组件的生命状态,状态是一种枚举类型里面包含两个值,一个是是否可以利用(这个值得作用时候来判断在某种状态下是否可以执行后续方法),第二个值是状态的属性值字符串变量(用来根据进行判断比较调用状态对应的方法)

standardHost.java

@Override
public final synchronized void init() throws LifecycleException{
  
    try {
        //设置状态为INITIALIZING
        setStateInternal(LifecycleState.INITIALIZING, null, false);
        initInternal();//这是一个抽象类其实现方法在具体的实现类
        //设置状态为INITIALIZED
        setStateInternal(LifecycleState.INITIALIZED, null, false);
    } catch (Throwable t){
        ………
    }
}
 
public enum LifecycleState {
    。。。。。。
    INITIALIZED(false, Lifecycle.AFTER_INIT_EVENT)
。。。。。。
    private final boolean available;
    private final String lifecycleEvent;

   private LifecycleState(boolean available,String lifecycleEvent) {
    this.available = available;
    this.lifecycleEvent= lifecycleEvent;
   }
}
 
public static final String AFTER_INIT_EVENT = "after_init";

  ②在设置声明状态之后,根据状态字符串常量值继续调用fireLifecycleEvent方法,在其中根据LifecycleSupport的句柄lifecycle调用fireLifecycleEvent

LifecycleBase.java
private synchronized void setStateInternal(LifecycleStatestate,
        Object data, boolean check) throws LifecycleException{

    this.state = state;
    String lifecycleEvent =state.getLifecycleEvent();
    if (lifecycleEvent!= null) {
        fireLifecycleEvent(lifecycleEvent,data);
    }
}
 
LifecycleBase.java
protected void fireLifecycleEvent(String type, Object data) {
    lifecycle.fireLifecycleEvent(type,data);
}

  ③fireLifecycleEvent方法则具体实现将当前组件以及状态字符串常量属性和数据封装到LifecycleEvent实例作为形式参数传递给其所有监听器对象并调用其具体方法

LifecycleSupport.java

public void fireLifecycleEvent(String type, Object data) {
    LifecycleEvent event = new LifecycleEvent(lifecycle, type,data);
    for (LifecycleListenerlistener : listeners) {
        listener.lifecycleEvent(event);
    }
}

1.3.3  监听器实现过程

在这里以HostConfig为例,看其lifecycleEvent方法实现过程可以看出其根据组件不同的状态会调用不同的方法来进行实现。

@Override
public void lifecycleEvent(LifecycleEvent event) {
    try {
        host = (Host)event.getLifecycle();
        if (host instanceof StandardHost){
            setCopyXML(((StandardHost) host).isCopyXML());
           。。。。。。。
        }
    } catch (ClassCastExceptione) {
       。。。。。。
    }
    if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) {
        check();
    } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
        beforeStart();
    } else if (event.getType().equals(Lifecycle.START_EVENT)) {
        start();
    } else if (event.getType().equals(Lifecycle.STOP_EVENT)) {
        stop();
    }
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏技术博客

设计模式之四(抽象工厂模式第一回合)

首先关于抽象工厂模式的学习,我们需要慢慢的,由浅入深的进入。不能单刀直入,否则可能达不到预期学明白的目标。

661
来自专栏依乐祝

Net Core集成Exceptionless分布式日志功能以及全局异常过滤

这篇文章有一部分内容翻译自官方文档,[点我阅读][https://github.com/exceptionless/Exceptionless.Net/wiki...

301
来自专栏WindCoder

Angular6自定义表单控件方式集成Editormd

曾经找到过“Editor.md”,看之心喜,一直想在Angular中集成下这款markdownpad编辑器玩,在网上也只找到一篇通过指令集成的,虽然可以实现,但...

532
来自专栏玩转前端

flutter接入现有的app详细介绍

接入的方式,我是参考的官方的介绍文档,我这里尝试的是android的接入方式,还算比较顺利。

1343
来自专栏向治洪

React Native在Android平台运行gif的解决方法

概述 目前RN在Android平台上不支持gif格式的图片,而在ios平台是支持的,期待以后的版本中系统也是可以默认支持Android的。首先说下在ios平台怎...

1766
来自专栏林德熙的博客

WPF 播放 gif

本文告诉大家如何在 WPF 播放 Gif 图片,提供了几个方法进行播放,包括比较性能。

351
来自专栏AhDung

【C#】让DataGridView输入中实时更新数据源中的计算列

本文适用Winform开发,且DataGridView的数据源为DataTable/DataView的情况。

792
来自专栏大内老A

编写T4模板进行代码生成无法避免的两个话题:"Assembly Locking"&"Debug"

在这之前,我写了一系列关于代码生成和T4相关的文章,而我现在也试图将T4引入我们自己的开发框架。在实践中遇到了一些问题,也解决了不少问题。如果你也在进行T4相关...

1767
来自专栏肖蕾的博客

关于AndroidStudio混淆打包 proguard-rules.pro 的配置关于AndroidStudio混淆打包 proguard-rules.pro 的配置

1072
来自专栏java闲聊

WebMagic初探,了解爬虫

1413

扫描关注云+社区