Tomcat8源码笔记(一)Lifecycle接口
第一次阅读Tomcat8源码,就以Lifecycle作为笔记阅读的开篇吧,一千个读者就有一千个哈姆雷特,每个人都Tomcat的理解都不同,如果不记录一次Tomcat源码可能忘了就忘了. 断断DEBUG了几天,决定从Lifecycle开始记录.
LifeCycle接口定义如下:
个人理解:Lifecycle接口定义了生命周期描述的字符常量,初始化之前、初始化之后、启动、启动之前、启动之后、停止、停止之前、停止之后、销毁之前、销毁之后等等;定义了生命周期监听器的三个方法,添加监听器、获得组件上监听器以及移除监听器;定义了组件的四个方法,初始化、启动、停止、销毁;定义了获取当前组件生命状态、生命状态名称;
LifecycleState是枚举,描述着声明周期的状态
Lifecycle接口实现类中比较重要LifecycleBase,以及LifecycleSupport类.
三者之间关系大概这样:LifecycleBase继承Lifecycle,且持有LifecycleSupport属性,LifecycleSupport也持有Lifecycle属性.
LifecycleBase抽象类
LifecycleBase持有LifecycleSupport实例lifecycle,而lifecycle本身持有的是Lifecycle类型,也就意味着如果有一个LifecycleBase的实例A,那A的lifecycle属性也持有A,我有你,你也有我. LifecycleBase实现了Lifecycle的监听器的方法,全部是对LifecycleSupport进行操作;LifecycleBase包括实现类默认创建的时候状态state都是LifecycleState.NEW.
LifecycleSupport类
LifecycleSupport持有Lifecycle实例,以及一个LifecycleListener集合listeners,所有添加、查找所有监听器、移除监听器、触发监听事件都是通过listeners来完成.
Tomcat的Lifecycle,如果要说设计模式,我觉得 观察者模式应该合适些. 观察者模式又被称为源-收听者模式(Listener),百度百科这么介绍该设计模式 : 一个目标物件管理所有依赖于他的观察者物件,并且在他本身状态发生改变时主动发出通知,通常用于事件处理系统。所以,这是我觉得Lifecycle可以称为观察者模式的原因,下面是Tomcat中StandardServer启动的过程,fireLifecycleEvent,Server主动去通知它的LifecycleListener,执行相应处理逻辑。
简单写个类似的例子,描述下我认为的观察者模式,一个考试Exam,一个闹钟类RingBell,闹钟一直在走,当闹钟到11.25分就去通知考试开始,中间过程省略一直到收卷结束。
Exam考试类
public class Exam implements Lifecycle { public void init() { System.out.println("监考老师分发考卷"); } public void start() { System.out.println("监考老师: 考试开始,大家可以做题了"); } public void stop() { System.out.println("监考老师:时间到,停止答题"); } public void destroy(){ System.out.println("监考老师收完卷子走人"); } private LifecycleSupport lifecycle=new LifecycleSupport(this); public void addLifecycleListener(final LifecycleListener listener) { lifecycle.addLifecycleListener(listener); } public LifecycleListener[] findLifecycleListeners() { return lifecycle.findLifecycleListeners(); } public void removeLifecycleListener(final LifecycleListener listener) { lifecycle.removeLifecycleListener(listener); } public LifecycleState getState() { return null; } public String getStateName() { return null; } }
RingBell类
public class RingBell implements Lifecycle { private boolean flag=true; public void setFlag(final boolean flag) { this.flag = flag; } private LifecycleSupport lifecycle=new LifecycleSupport(this); public void addLifecycleListener(final LifecycleListener listener) { lifecycle.addLifecycleListener(listener); } public LifecycleListener[] findLifecycleListeners() { return lifecycle.findLifecycleListeners(); } public void removeLifecycleListener(final LifecycleListener listener) {lifecycle.removeLifecycleListener(listener); } public void start() throws LifecycleException { } public void stop() throws LifecycleException { } public void destroy() throws LifecycleException {} public LifecycleState getState() { return null; } public String getStateName() { return null; } public void init() throws LifecycleException { System.out.println("时钟慢慢走动....."); while(flag){ Date now = new Date(); System.out.println(new SimpleDateFormat("hh:mm:ss").format(now)); if(now.getHours()==11 && now.getMinutes()== 25 && now.getSeconds()==0){ lifecycle.fireLifecycleEvent(Lifecycle.AFTER_INIT_EVENT,null); }else if(now.getHours()==11 && now.getMinutes()== 25 && now.getSeconds()== 2){ lifecycle.fireLifecycleEvent(Lifecycle.START_EVENT,null); }else if(now.getHours()==11 && now.getMinutes()== 25 && now.getSeconds()==4){ lifecycle.fireLifecycleEvent(Lifecycle.STOP_EVENT,null); }else if(now.getHours()==11 && now.getMinutes()== 25 && now.getSeconds()== 6){ lifecycle.fireLifecycleEvent(Lifecycle.AFTER_DESTROY_EVENT,null); }else if(now.getHours()==11 && now.getMinutes()== 25 && now.getSeconds()== 8){ lifecycle.fireLifecycleEvent(Lifecycle.AFTER_DESTROY_EVENT,null); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("谁把时钟关了"); } }
ExamListener
public class ExamListener implements LifecycleListener { private Exam exam; public ExamListener(final Exam exam) { this.exam = exam; } public void lifecycleEvent(final LifecycleEvent event) { if(event.getType().equals(Lifecycle.AFTER_INIT_EVENT)){ exam.init(); }else if(event.getType().equals(Lifecycle.START_EVENT)){ exam.start(); }else if(event.getType().equals(Lifecycle.STOP_EVENT)){ exam.stop(); }else if(event.getType().equals(Lifecycle.AFTER_DESTROY_EVENT)){ exam.destroy(); RingBell ringBell= (RingBell) event.getLifecycle(); ringBell.setFlag(false); } } }
测试方法:
public static void main(String[] args) throws LifecycleException { Exam exam = new Exam(); RingBell ringBell=new RingBell(); ringBell.addLifecycleListener(new ExamListener(exam)); ringBell.init(); }
解释说明: RingBell作为被观察对象,观察对象就是ExamListener, RingBell持有观察对象ExamListener,当RingBell状态改变(当前时间改变),就去通知观察者们,观察者们就触发事件,开始考试啊、结束考试等等;
这里的观察者不是具象的观察者对象,而是监听器类型LifecycleListener,通过监听器来使Exam做出响应处理,事件驱动机制。测试效果如下:
注意 RingBell对象 不合适 直接持有Exam的引用, 耦合性太高,假如再来一个观察者监考老师,监考老师需要考试期间来巡查,那我们只需要添加一个LifecycleListener实现类即可,不需要让RingBell持有这个监考老师监听器。
Lifecycle代表了Tomcat的组件的生命周期,定义过init、start、stop、destroy等四个重要的方法。而Tomcat的重要组件全部都实现了LifecycleBase接口,继承了LifecycleBase接口,下图是利用IDEA画出来的继承关系:
LifecycleBase抽象类采用了模板设计模式,听说过采用了模板设计模式的有Arrays.sort方法、Servlet的service方法,模板设计模式的好处就是 统一按照模板执行,共性的基础上个性的地方,再各自处理。
LifecycleBase的init模板方法:
state默认为LifecycleState.NEW,所以第一步的目的是为了防止多次调用init方法,Tomcat组件基本上初始化一次就够了。
init模板共性的地方就是设置当前组件状态,LifecycleState.INITIALIZING以及LifecycleState.INITIALIZED,个性之处在于initInternal,不同组件实现逻辑就是这里体现的。
而共性的设置组件状态的目的呢?接着往下看。
设置组件状态,check为true会再次校验组件状态,一般check都为false. 更新组件的状态,之后就是观察者模式的应用,主动通知组件上左右的监听器LifecycleListener,触发相应的事件。
通过上面两段代码分析,一个组件init初始化大致过程:组件上所有监听器,如果有的话触发LifecycleState.INITIALIZING,也就是before_init, 接着initInternal,就是组件自己会重写的方法,接着触发组件上监听器的LifecycleState.INITIALIZED,也就是after_init类型事件!
LifecycleBase的start模板方法
首先检查组件状态,如果已经处于启动相关状态,before_start/after_start/start状态的话,打印日志并且不再启动;
组件如果还没初始化呢,那赶紧初始化;组件初始化、启动失败了,赶紧停止组件;到这里,如果组件不是初始化完成或者停止的状态,那就有问题了,启动中?启动了? 正要启动组件,你启动好了,抛出异常;
上述检查都没问题,那设置状态LifecycleState.STARTING_PREP,也就是before_start,目的不用多说了吧,启动组件上监听器,触发before_start的事件啊,接着才是各个组件个性的startInternal,启动完成没有问题,那就设置状态LifecycleState.STARTED,也就是after_start,目的同样启动组件监听器触发after_start事件。
剩下两个stop 、destory模板方法,不用我说肯定是类似的,这里就不多此一举了,毕竟我们连Tomcat启动干了啥都不知道,相比于分析停止、摧毁的模板方法,还是留时间分析Tomcat的启动吧。
总结
感觉自己这样一整理舒畅多了,见识两种设计模式,也请求了Tomcat的组件的初始化、启动流程要干啥,从哪里分析了,核心就是Lifecycle接口以及LifecycleBase以及LifecycleListener,接下来,只需要关注组件上有哪些监听器、初始化initInternal、启动startInternal过程干了啥。