前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >tomcat源码解读二 tomcat的生命周期

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

作者头像
cfs
发布2018-03-08 15:32:38
1.1K0
发布2018-03-08 15:32:38
举报
文章被收录于专栏:编码小白

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

部分代码如下:

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
@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

代码语言:javascript
复制
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

代码语言:javascript
复制
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方法实现过程可以看出其根据组件不同的状态会调用不同的方法来进行实现。

代码语言:javascript
复制
@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();
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017年11月13日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1    生命周期
    • 1.1    观察者模型
      • 1.2    生命周期时序图
        • 1.3    生命周期源码解读
          • 1.3.1  添加监听器
          • 1.3.2  唤醒监听器
          • 1.3.3  监听器实现过程
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档