最近在阅读“how tomcat works”这本书,结合tomcat7的源码进行学习。对于学习的收获,将通过“tomcat学习系列”记录下来,和大家一起分享和交流,也算对自己学习的一种促进。闲话不多说,正文开始。 
    Catalina内部由多个组件组成,启动时各个组件都需要启动,关闭时需要各个组件关闭。如何协作各个组件的初始化、启动、停止、销毁等的一致性,通过各组件实现Lifecycle这个接口来完成。各组件在启动、关闭等重要生命周期中,会发出事件通知,通知已注册的观察者做事件处理。

一、主要类图

二、主要类介绍

1) Lifecycle 
Lifecycle表示生命周期概念的接口。定义了组件生命周期中的通用事件(START_EVENT、STOP_EVENT等)和接口(start、stop、destroy、addLifecycleListener、removeLifecycleListener等)。组件可以通过实现Lifecyecle接口,完成组建的重要生命周期实现和组建的观察者管理。 
2)LifecycleState 
组件的有效状态枚举。定义了组件生命周期中的状态和状态对应的事件。当状态发生改变时,会发出相应事件,通知观察者进行处理。 
3)LifecycleBase 
Lifecycle接口的抽象的基础实现类,主要实现了制定启动和停止状态相关的转换规则。Lifecycle接口的默认实现,实现init、start、stop、destroy等方法。对观察者的增加、查找和删除等操作会适配器方式,由组合的LifecycleSupport实例来完成。此外还提供了生成LifecycleEvent事件的接口 
4)LifecycleSupport 
用来帮助传送消息给监听器的辅助类。观察者的实际管理类,实现观察者的注册、删除、查询、调用等操作。 
5)LifecycleListener 
用来监听组件状态变化并触发相应事件的监听器。生命周期的观察者,定义了观察者的事件处理接口lifecycleEvent(LifecycleEvent event)。 
6)ServerLifecycleListener 
实际的观察者,实现了事件处理接口。 
7)LifecycleEvent 
组件状态变化时触发的事件。观察者使用的参数,它封装了事件来源、事件类型和事件数据,使得观察者可以按事件来源和事件类型分类处理事件。

8)LifecycleException

生命周期相关异常。

三、下面分别对这几个类进行解析

Lifecycle

这个接口声明了能对组件施加影响的生命周期事件类型常量,可以分为在状态中、状态前和状态后(不是每个状态都有这相应的三种情况)。包含的状态有初始化、启动、停止、销毁、配置,以及一个特殊的阶段性状态,具体常量如下:

    public static final String BEFORE_INIT_EVENT = "before_init";
public static final String AFTER_INIT_EVENT = "after_init";
public static final String START_EVENT = "start";
public static final String BEFORE_START_EVENT = "before_start";
public static final String AFTER_START_EVENT = "after_start";
public static final String STOP_EVENT = "stop";
public static final String BEFORE_STOP_EVENT = "before_stop";
public static final String AFTER_STOP_EVENT = "after_stop";
public static final String AFTER_DESTROY_EVENT = "after_destroy";
public static final String BEFORE_DESTROY_EVENT = "before_destroy";
public static final String PERIODIC_EVENT = "periodic";
public static final String CONFIGURE_START_EVENT = "configure_start";
public static final String CONFIGURE_STOP_EVENT = "configure_stop";

Lifecycle对外提供的方法主要分为两大类,一类是对监听器的管理,另一类是生命周期的各个状态,需要根据状态来做相应动作和触发事件。

 //监听器的添加、查找与删除操作
public void addLifecycleListener(LifecycleListener listener);
public LifecycleListener[] findLifecycleListeners();
public void removeLifecycleListener(LifecycleListener listener); //触发各个状态相关的生命周期事件来进行准备和善后处理
public void init() throws LifecycleException;
public void start() throws LifecycleException;
public void stop() throws LifecycleException;
public void destroy() throws LifecycleException; //获取组件当前状态
public LifecycleState getState();
public String getStateName();

实现了Lifecycle接口的非常之多,具体可以去看它继承树,这里给出一些实现或继承该接口的关键类或接口。

LifecycleListener

LifecycleListener表示对某一个生命周期事件的监听。这个接口非常简单,只有一个方法。

 //定义某一事件发生时需要的行为
public void lifecycleEvent(LifecycleEvent event);

LifecycleEvent

LifecycleEvent继承自Java的事件对象EventObject,是一个简单的类,由事件相关组件、事件的类型和事件相关数据组成。

public final class LifecycleEvent extends EventObject {
private static final long serialVersionUID = 1L;
private final Object data;
private final String type; public LifecycleEvent(Lifecycle lifecycle, String type, Object data) {
super(lifecycle);
this.type = type;
this.data = data;
} public Object getData() {
return (this.data);
} public Lifecycle getLifecycle() {
return (Lifecycle) getSource();
} public String getType() {
return (this.type);
}
}

LifecycleException

LifecycleException表示一个生命周期相关的异常,继承自Java的Exception类,提供了多种不同的构造函数,此外不能自定义它的子类。

public final class LifecycleException extends Exception {
private static final long serialVersionUID = 1L; public LifecycleException() {
super();
} public LifecycleException(String message) {
super(message);
} public LifecycleException(Throwable throwable) {
super(throwable);
} public LifecycleException(String message, Throwable throwable) {
super(message, throwable);
}
}

LifecycleState

LifecycleState枚举出了一个组件合法的生命周期状态,并对外提供两个参数,一个是获取生命周期事件,即在该状态下应该调用哪类生命周期事件,另一个是在该状态下能否调用组件除了getter/setter和生命周期方法外的其他public方法。

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;
}
}

你会发现在枚举中有很多之前没有提到的状态,下面列出各个状态之间的转换关系:

主要状态有:初始(初始状态,初始中,初始后),启动(启动前,启动中,启动后),停止(停止前,停止中,停止后),销毁(销毁前,销毁中,销毁后)

LifecycleSupport

LifecycleSupport是用来将事件通知给一个组件的所有监听器的辅助类。它包含了组件和该组件所有的监听器。其中监听器用了线程安全的CopyOnWriteArrayList来存储,主要的事件通知函数如下:

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

LifecycleBase

LifecycleBase是实现了Lifecycle的抽象类。它通过持有一个LifecycleSupport来管理监听器。具体的状态函数使用了模板方法模式,LifecycleBase规定了个状态之间的转换规则(是否合法以及状态间的自动转换等,具体参看LifecycleState中的状态转换图),而让用户继承的子类来实现具体的操作。由于代码较多,举一个start方法的例子。

public final synchronized void start() throws LifecycleException {

        if (LifecycleState.STARTING_PREP.equals(state) ||
LifecycleState.STARTING.equals(state) ||
LifecycleState.STARTED.equals(state)) { if (log.isDebugEnabled()) {
Exception e = new LifecycleException();
log.debug(sm.getString("lifecycleBase.alreadyStarted",
toString()), e);
} else if (log.isInfoEnabled()) {
log.info(sm.getString("lifecycleBase.alreadyStarted",
toString()));
} return;
} if (state.equals(LifecycleState.NEW)) {
init();
} else if (state.equals(LifecycleState.FAILED)){
stop();
} else if (!state.equals(LifecycleState.INITIALIZED) &&
!state.equals(LifecycleState.STOPPED)) {
invalidTransition(Lifecycle.BEFORE_START_EVENT);
} setStateInternal(LifecycleState.STARTING_PREP, null, false); try {
//调用用户实现的方法
startInternal();
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
setStateInternal(LifecycleState.FAILED, null, false);
throw new LifecycleException(
sm.getString("lifecycleBase.startFail",toString()), t);
} if (state.equals(LifecycleState.FAILED) ||
state.equals(LifecycleState.MUST_STOP)) {
stop();
} else {
// Shouldn't be necessary but acts as a check that sub-classes are
// doing what they are supposed to.
if (!state.equals(LifecycleState.STARTING)) {
invalidTransition(Lifecycle.AFTER_START_EVENT);
} setStateInternal(LifecycleState.STARTED, null, false);
}
} //用户实现的抽象方法
protected abstract void startInternal() throws LifecycleException;

四、生命周期重要过程

1. 观察者注册 
观察者的注册可以通过xml方式配置,也可以通过直接调用Lifecycle的观察者添加方法。tomcat配置文件目录conf下面的server.xml中观察者配置如下:

  1. <Server port="8005" shutdown="SHUTDOWN">
  2. <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  3. <Listener className="org.apache.catalina.core.JasperListener" />
  4. <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  5. <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  6. ...
  7. </Server>

LifecycleSupport的观察者注册代码如下:

  1. public final class LifecycleSupport {
  2. // 观察者数组
  3. private LifecycleListener listeners[] = new LifecycleListener[0];
  4. ...
  5. public void addLifecycleListener(LifecycleListener listener) {
  6. synchronized (listenersLock) {
  7. LifecycleListener results[] =
  8. new LifecycleListener[listeners.length + 1];
  9. for (int i = 0; i < listeners.length; i++)
  10. results[i] = listeners[i];
  11. results[listeners.length] = listener;
  12. listeners = results;
  13. }
  14. }
  15. }

观察者是通过数组来维护,每次增加一个新的观察者,都需要将当前数组长度加1,将原来数组内容拷贝到新的数组中。对这里的设计我比较困惑,为什么采用这种数组扩容方式,这样每次增加新增观察者都需要数组拷贝,影响性能。可能的一个原因是,考虑到观察者数目少和新增的次数少,这种方式可以减少内存占用。

2. 通知观察者 
组件的生命周期中状态发生改变时,都会发出事件,通知观察者处理。下面以LifecycleBase中init()方法举例说明。

  1. public abstract class LifecycleBase implements Lifecycle {
  2. private LifecycleSupport lifecycle = new LifecycleSupport(this);
  3. // 当前状态
  4. private volatile LifecycleState state = LifecycleState.NEW;
  5. public synchronized final void init() throws LifecycleException {
  6. if (!state.equals(LifecycleState.NEW)) {
  7. invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
  8. }
  9. // 状态转移到INITIALIZING,会发送事件
  10. setState(LifecycleState.INITIALIZING);
  11. initInternal();
  12. setState(LifecycleState.INITIALIZED);
  13. }
  14. protected synchronized void setState(LifecycleState state, Object data) {
  15. ...
  16. this.state = state;
  17. // state为枚举类型,获取该枚举值对应的事件类型
  18. String lifecycleEvent = state.getLifecycleEvent();
  19. if (lifecycleEvent != null) {
  20. // 发起事件通知
  21. fireLifecycleEvent(lifecycleEvent, data);
  22. }
  23. }
  24. // 调用LifecycleSupport进行事件处理
  25. protected void fireLifecycleEvent(String type, Object data) {
  26. lifecycle.fireLifecycleEvent(type, data);
  27. }
  28. }

LifecycleSupport中的事件处理方法如下:

  1. public void fireLifecycleEvent(String type, Object data) {
  2. // 包装事件类型和数据
  3. LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
  4. // 循环,通知所有观察者进行事件处理
  5. LifecycleListener interested[] = listeners;
  6. for (int i = 0; i < interested.length; i++)
  7. interested[i].lifecycleEvent(event);
  8. }

3. 观察者事件处理 
以ServerLifecycleListener为例,说明观察者事件处理过程。 
public class ServerLifecycleListener 
    implements ContainerListener, LifecycleListener, PropertyChangeListener { 
    ... 
    public void lifecycleEvent(LifecycleEvent event) { 
        Lifecycle lifecycle = event.getLifecycle(); 
        if (Lifecycle.START_EVENT.equals(event.getType())) { 
                if (lifecycle instanceof Server) { 
                    ... 
                } 
                if( lifecycle instanceof Service ) { 
                   ... 
                }           
                if (lifecycle instanceof StandardContext){ 
                    ... 
                } 
            
        } else if (Lifecycle.AFTER_STOP_EVENT.equals(event.getType())) { 
                ... 
        } 
    } 

观察者可以通过事件来源(lifecycle)和事件类型(eventType)对事件分类处理。

四、 总结 
tomcat中事件处理机制比较灵活,在日常工作的设计中值得借鉴,比如下面的业务场景:对客户投诉的创建、撤销、终止等,可以采用如下处理方式: 
--生命周期管理-- 
1. 创建统一的投诉业务生命周期Lifecycle,如create、cancel、destroy等。 
2. 定义投诉业务的状态枚举类(对应tomcat中LifecycleState),枚举类中定义每个状态对应的事件类型。 
--观察者注册-- 
3. 创建观察者管理service(对应tomcat中的LifecycleSupport)。观察者列表可以通过spring bean方式注入。 
--观察者通知-- 
4. 在生命周期中状态改变时,比如投诉创建时,发送事件通知,调用观察者管理service,通知观察者处理。 
5. 包装观察者所需要的数据(对应tomcat中的LifecycleEvent),如事件来源、类型等,供观察者使用。 
--观察者处理-- 
6. 定义实际观察者,按事件来源和类型分别做业务处理,比如投诉创建时,将投诉发生时用户的业务开通快照记录下来。

本文转自:https://blog.csdn.net/u013291394/article/details/50180753  http://learnworld.iteye.com/blog/1013751

tomcat事件处理机制的更多相关文章

  1. java 事件处理机制:按下上下左右键控制小球的运动

    /** * 加深对事件处理机制的理解 * 通过上下左右键来控制一个小球的位置 */package com.test3;import java.awt.*;import javax.swing.*;im ...

  2. Android事件处理机制

    包括监听和回调两种机制. 1. 基于监听的事件处理: 事件监听包含三类对象,事件源,事件,事件监听器.Android的事件处理机制是一种委派式(Delegation)事件处理方式:普通组件(事件源)将 ...

  3. 图解Tomcat类加载机制

    说到本篇的tomcat类加载机制,不得不说翻译学习tomcat的初衷. 之前实习的时候学习javaMelody的源码,但是它是一个Maven的项目,与我们自己的web项目整合后无法直接断点调试.后来同 ...

  4. Android的两种事件处理机制

    UI编程通常都会伴随事件处理,Android也不例外,它提供了两种方式的事件处理:基于回调的事件处理和基于监听器的事件处理. 对于基于监听器的事件处理而言,主要就是为Android界面组件绑定特定的事 ...

  5. Android的Touch事件处理机制

    Android的Touch事件处理机制比较复杂,特别是在考虑了多点触摸以及事件拦截之后. Android的Touch事件处理分3个层面:Activity层,ViewGroup层,View层. 首先说一 ...

  6. IOS事件处理机制(关于触发者和响应者的确认)

    事件处理机制 在iOS中发生触摸后,事件会加入到UIApplication事件队列(在这个系列关于iOS开发的第一篇文章中我们分析iOS程序原理的时候就说过程序运行后UIApplication会循环监 ...

  7. Java Swing事件处理机制

    Java Swing的事件处理机制 Swing GUI启动后,Java虚拟机就启动三个线程,分别为主线程,事件派发线程(也是事件处理线程)和系统工具包线程. 主线程 :负责创建并显示该程序的初始界面: ...

  8. Qt事件处理机制

    研一的时候开始使用Qt,感觉用Qt开发图形界面比MFC的一套框架来方便的多.后来由于项目的需要,也没有再接触Qt了.现在要重新拾起来,于是要从基础学起. Now,开始学习Qt事件处理机制. 先给出原文 ...

  9. core java 8~9(GUI & AWT事件处理机制)

    MODULE 8 GUIs--------------------------------GUI中的包: java.awt.*; javax.swing.*; java.awt.event.*; 要求 ...

随机推荐

  1. Windows I/O完成端口

    内容: 1.基本概念     2.WINDOWS完成端口的特点     3.完成端口(Completion Ports )相关数据结构和创建     4.完成端口线程的工作原理     5.Windo ...

  2. js实现new Date(),时间对象和时间戳操作

    1.js中实现时间date对象 var myDate = new Date();//获取系统当前时间,结果:Wed Aug 09 2017 00:00:00 GMT+0800 (中国标准时间) 2.获 ...

  3. word使用宏定义来统一设置图片大小

    1. 首先手动拖拽将图片调到需要的格式,点击图片在格式选项中查看图片的宽高 2. 视图中点击宏新建 3. 编辑框中输入以下代码并保存,由于我只需要统一宽度,所以将统一高度的代码注释 Sub 图片格式统 ...

  4. iOS GCD中级篇 - dispatch_group的理解及使用

    上一篇GCD基础篇,以及同步.异步,并发.并行几个概率的理解 关于dispatch_group的概念以及几种场景下的使用 1.关于dispatch_group 把一组任务提交到队列中,这些队列可以不相 ...

  5. HDUOJ-------2149Public Sale

    Public Sale Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  6. HDUOJ----Safecracker(1015)

    Safecracker Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Tota ...

  7. 【LeetCode】164. Maximum Gap (2 solutions)

    Maximum Gap Given an unsorted array, find the maximum difference between the successive elements in ...

  8. APK 本地化和去广告

    APK 本地化       说起APK的汉化,目前大部分教程都是让用Hex Workshop或者Android ResEdit来做.但是实际操作后,就会发现: 1.Hex Workshop操作繁琐,经 ...

  9. SQL Server 2005/2008遍历所有表更新统计信息

    DECLARE UpdateStatisticsTables CURSOR READ_ONLY FOR 02   SELECT sst.name, 03          Schema_name(ss ...

  10. Android中实现下拉刷新

    需求:项目中的消息列表界面要求实现类似sina微博的下拉刷新: 思路:一般的消息列表为ListView类型,将list加载到adapter中,再将adapter加载到 ListView中,从而实现消息 ...