最近在阅读“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. Linux 系统使用 iso 镜像文件或光盘配置本地YUM 源的最简单方式

    1.分配光驱 选择本地的iso系统镜像文件,或者在光驱中放入系统安装盘.之后,在桌面可以看到RHEL-7.2-Server的光盘图标. 2.查看光驱挂载的位置 使用df -h 命令可以看到光驱或镜像文 ...

  2. Windwos在cmd如何复制文本

    生活的琐事,总是要解决. 01.Win+R打开运行窗口 cmd--回车 02. 勾选快速编辑模式 注意: 快速编辑模式就是可以Ctrl+c(复制).Ctrl+v(粘贴)

  3. 深入PHP内核之array_multisort

    这个函数是我第一次看手册的时候,没看明白是怎么回事,所以有必要记录一下 用法 bool array_multisort ( array &$arr [, mixed $arg = SORT_A ...

  4. Fork me on GitHub

    <a href="https://github.com/yadongliang"><img style="position: absolute; top ...

  5. 去掉cb中括号的匹配

    Settings->Editor->General settings->Indent options->Brace completion``

  6. HDUOJ---大菲波数

    大菲波数 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  7. java提高篇之详解内部类

    可以将一个类的定义放在另一个类的定义内部,这就是内部类. 内部类是一个非常有用的特性但又比较难理解使用的特性(鄙人到现在都没有怎么使用过内部类,对内部类也只是略知一二). 第一次见面 内部类我们从外面 ...

  8. python学习笔记——高阶函数map()

    满足以下两点中任意一点,即为高阶函数: 1.函数接收一个或多个函数作为参数 2.函数返回一个函数 1 描述 用函数和可迭代对象中每一个元素作为参数,计算出新的迭代对象 map() 会根据提供的函数对指 ...

  9. pylot 学习笔记

    安装步骤 1.下载pylot 版本是1.26,文件名是:pylot_1.26.zip 2.下载python 版本是2.5,文件名是:python-2.5.msi 3.下载numpy 版本是1.4.1, ...

  10. C#开发Windows Services服务--服务安装失败的解决办法

    问题1:“System.Security.SecurityException:未找到源,但未能搜索某些或全部事件日志.不可访问的日志: Security.” 正在运行事务处理安装. 正在开始安装的“安 ...