Tomcat7源码分析(二)组件生命周期详解
程序员文章站
2022-05-24 11:30:42
...
在tomcat中起到生命周期的核心接口是Lifecycle看一下这个接口的方法签名:
这个接口定义了所有组件可能处于的所有状态、增加获取删除监听器操作、组件初始化,开启,停止,注销操作和获取当前状态操作。
在Lifecycle接口中所定义的状态还被封装到了一个枚举类中,可以看一下LifecycleState的源码:
从以上源码可见LifecycleState枚举类就是对Lifecycle接口中的状态进行了封装。另外加了是否可用标志。
下面从我们所熟悉的StandardServer类入手开始讨论这些组件是怎么被初始化以及怎么被开启的。看一下StandardServer的继承图解:
至此就引出了一个问题,LifecycleBase是个什么类。打开这个类的源码首先可以看到它实现了Lifecycle接口,即它是管理组件生命周期的最顶层的类。一般像这种高层次的类都是抽象的,这个类也不例外,它也是抽象的。
下面开始讨论这个类的方法,首先继承LifecycleBase的底层组件类比如StandardServer它是不需要重写init,start,stop这三个方法的。因为这三个方法定义了组件状态转换的共性。比如init方法,所有组件在初始化时都要执行这个公共方法。先贴一下这个方法的源码:
其中有两点需要重点关注:
1)setStateInternal:该方法的作用是重新设置该组件的状态。并且在状态改变时还伴随着事件监听器的执行。查看setStateInternal的代码不难发现它的核心代码如下:
先改变组件状态,然后查看该状态是否需要被监听器监听。如果被监听器监听就执行监听器。但是执行监听器说起来容易,它是怎么来的,它的监听机制又是什么?
现在追上这个方法看看它的实现过程:
这个lifecycle又是什么东西?它是LifecycleSupport类的一个实例。其实LifecycleBase是LifecycleSupport的一个代理类。所有监听器有关的方法LifecycleBase都是调用的LifecycleSupport中的方法。可以看一下LifecycleSupport的方法签名:
lifecycle是指该LifecycleSupport类是为哪个实现lifecycle接口的类服务的。listeners[]是监听器数组,addLifecycleListener是增加监听器,在tomcat容器启动时,使用Digester技术(没听过没关系,只要知道它是读取配置文件然后根据配置文件实例化对象就行)读取server.xml文件中的<Listener>标签,然后调用addLifecycleListener将配置的Listener添加到listeners[]中。removeLifecycleListener是移出监听器。fireLifecycleEvent是循环执行监听器数组中的每一个监听器。上面谈到的状态改变时就是执行的这个fireLifecycleEvent方法。
看到这里也许有的朋友已经忘了上文的init方法了,千万注意到此这只是谈到init方法中需要注意两点的第一点。那么现在开始第二点:
2)initInternal方法。它是个抽象方法也就是说该方法必须由子类重写。首先看它的直接子类LifecycleMBeanBase。看到这类的名字就能想到它可能与javabean管理有关。的确他复写了initInternal方法,其目的就是将该组件注册到JMX服务器中。对于具体注册过程先不做过多讨论,之后更新还会详细说明。StandardServer也重写了initInternal方法。并且第一行是:
调用父类也就是LifecycleMBeanBase类中的initInternal方法,这时候这句话是万万不能省的,如果省了就不能向JMX服务器注册对象了。这一点要跟eclipse中自动生成构造方法第一行super.init();可写可不写区分开。在子类中重点代码如下:
它执行了service的init方法。仔细回故上面的逻辑,整理一下思路,会发现tomcat的生命周期管理是何等的漂亮!
我将tomcat生命周期的实现过程从tomcat源码中抽离了出来,建立了一个小的Demo,有兴趣的朋友可以下载debug以此来整理思路,这样会更加直观。
地址:https://github.com/smallbug-vip/repo
这个接口定义了所有组件可能处于的所有状态、增加获取删除监听器操作、组件初始化,开启,停止,注销操作和获取当前状态操作。
在Lifecycle接口中所定义的状态还被封装到了一个枚举类中,可以看一下LifecycleState的源码:
public enum LifecycleState { NEW(false, null), INITIALIZING(false, Lifecycle.BEFORE_INIT_EVENT), INITIALIZED(false, Lifecycle.AFTER_INIT_EVENT), STARTING_PREP(false, Lifecycle.BEFORE_START_EVENT), STARTING(true, Lifecycle.START_EVENT), STARTED(true, Lifecycle.AFTER_START_EVENT), STOPPING_PREP(true, Lifecycle.BEFORE_STOP_EVENT), STOPPING(false, Lifecycle.STOP_EVENT), STOPPED(false, Lifecycle.AFTER_STOP_EVENT), DESTROYING(false, Lifecycle.BEFORE_DESTROY_EVENT), DESTROYED(false, Lifecycle.AFTER_DESTROY_EVENT), FAILED(false, null), MUST_STOP(true, null), MUST_DESTROY(false, null); private final boolean available; private final String lifecycleEvent; private LifecycleState(boolean available, String lifecycleEvent) { this.available = available; this.lifecycleEvent = lifecycleEvent; } public boolean isAvailable() { return available; } /** * */ public String getLifecycleEvent() { return lifecycleEvent; } }
从以上源码可见LifecycleState枚举类就是对Lifecycle接口中的状态进行了封装。另外加了是否可用标志。
下面从我们所熟悉的StandardServer类入手开始讨论这些组件是怎么被初始化以及怎么被开启的。看一下StandardServer的继承图解:
至此就引出了一个问题,LifecycleBase是个什么类。打开这个类的源码首先可以看到它实现了Lifecycle接口,即它是管理组件生命周期的最顶层的类。一般像这种高层次的类都是抽象的,这个类也不例外,它也是抽象的。
下面开始讨论这个类的方法,首先继承LifecycleBase的底层组件类比如StandardServer它是不需要重写init,start,stop这三个方法的。因为这三个方法定义了组件状态转换的共性。比如init方法,所有组件在初始化时都要执行这个公共方法。先贴一下这个方法的源码:
@Override public final synchronized void init() throws LifecycleException { if (!state.equals(LifecycleState.NEW)) { invalidTransition(Lifecycle.BEFORE_INIT_EVENT); } setStateInternal(LifecycleState.INITIALIZING, null, false); try { initInternal(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); setStateInternal(LifecycleState.FAILED, null, false); throw new LifecycleException( sm.getString("lifecycleBase.initFail",toString()), t); } setStateInternal(LifecycleState.INITIALIZED, null, false); }
其中有两点需要重点关注:
1)setStateInternal:该方法的作用是重新设置该组件的状态。并且在状态改变时还伴随着事件监听器的执行。查看setStateInternal的代码不难发现它的核心代码如下:
this.state = state; String lifecycleEvent = state.getLifecycleEvent(); if (lifecycleEvent != null) { fireLifecycleEvent(lifecycleEvent, data); }
先改变组件状态,然后查看该状态是否需要被监听器监听。如果被监听器监听就执行监听器。但是执行监听器说起来容易,它是怎么来的,它的监听机制又是什么?
现在追上这个方法看看它的实现过程:
protected void fireLifecycleEvent(String type, Object data) { lifecycle.fireLifecycleEvent(type, data); }
这个lifecycle又是什么东西?它是LifecycleSupport类的一个实例。其实LifecycleBase是LifecycleSupport的一个代理类。所有监听器有关的方法LifecycleBase都是调用的LifecycleSupport中的方法。可以看一下LifecycleSupport的方法签名:
lifecycle是指该LifecycleSupport类是为哪个实现lifecycle接口的类服务的。listeners[]是监听器数组,addLifecycleListener是增加监听器,在tomcat容器启动时,使用Digester技术(没听过没关系,只要知道它是读取配置文件然后根据配置文件实例化对象就行)读取server.xml文件中的<Listener>标签,然后调用addLifecycleListener将配置的Listener添加到listeners[]中。removeLifecycleListener是移出监听器。fireLifecycleEvent是循环执行监听器数组中的每一个监听器。上面谈到的状态改变时就是执行的这个fireLifecycleEvent方法。
看到这里也许有的朋友已经忘了上文的init方法了,千万注意到此这只是谈到init方法中需要注意两点的第一点。那么现在开始第二点:
2)initInternal方法。它是个抽象方法也就是说该方法必须由子类重写。首先看它的直接子类LifecycleMBeanBase。看到这类的名字就能想到它可能与javabean管理有关。的确他复写了initInternal方法,其目的就是将该组件注册到JMX服务器中。对于具体注册过程先不做过多讨论,之后更新还会详细说明。StandardServer也重写了initInternal方法。并且第一行是:
super.initInternal();
调用父类也就是LifecycleMBeanBase类中的initInternal方法,这时候这句话是万万不能省的,如果省了就不能向JMX服务器注册对象了。这一点要跟eclipse中自动生成构造方法第一行super.init();可写可不写区分开。在子类中重点代码如下:
// Initialize our defined Services for (int i = 0; i < services.length; i++) { services[i].init(); }
它执行了service的init方法。仔细回故上面的逻辑,整理一下思路,会发现tomcat的生命周期管理是何等的漂亮!
我将tomcat生命周期的实现过程从tomcat源码中抽离了出来,建立了一个小的Demo,有兴趣的朋友可以下载debug以此来整理思路,这样会更加直观。
地址:https://github.com/smallbug-vip/repo
上一篇: spring整合junit集成测试
下一篇: java类加载机制详解
推荐阅读
-
Tomcat源码分析 (二)----- Tomcat整体架构及组件
-
Laravel源码分析--Laravel生命周期详解
-
Vue.js 源码分析(十四) 基础篇 组件 自定义事件详解
-
Vue.js 源码分析(十二) 基础篇 组件详解
-
Vue.js 源码分析(三十一) 高级应用 keep-alive 组件 详解
-
Mapreduce源码分析(二):MapTask及LineRecordReader读取文件的工作机制,源码详解
-
Vue 2.0 源码分析(九) 生命周期详解
-
Vue.js 源码分析(十三) 基础篇 组件 props属性详解
-
element-ui switch组件源码分析整理笔记(二)
-
Vue.js 源码分析(二十九) 高级应用 transition-group组件 详解