tomcat学习系列---tomcat事件处理机制

Posted nizuimeiabc1

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了tomcat学习系列---tomcat事件处理机制相关的知识,希望对你有一定的参考价值。

最近在阅读“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接口的默认实现,实现init、start、stop、destroy等方法。对观察者的增加、查找和删除等操作会适配器方式,由组合的LifecycleSupport实例来完成。 
4)LifecycleSupport 
观察者的实际管理类,实现观察者的注册、删除、查询、调用等操作。 
5)LifecycleListener 
生命周期的观察者,定义了观察者的事件处理接口lifecycleEvent(LifecycleEvent event)。 
6)ServerLifecycleListener 
实际的观察者,实现了事件处理接口。 
7)LifecycleEvent 
观察者使用的参数,它封装了事件来源、事件类型和事件数据,使得观察者可以按事件来源和事件类型分类处理事件。 

三、生命周期重要过程 
1. 观察者注册 
观察者的注册可以通过xml方式配置,也可以通过直接调用Lifecycle的观察者添加方法。server.xml中观察者配置如下: 

Java代码  技术分享图片
  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的观察者注册代码如下: 

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


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

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

Java代码  技术分享图片
  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.   
  15.     protected synchronized void setState(LifecycleState state, Object data) {  
  16.         ...  
  17.         this.state = state;  
  18.         // state为枚举类型,获取该枚举值对应的事件类型  
  19.         String lifecycleEvent = state.getLifecycleEvent();  
  20.         if (lifecycleEvent != null) {  
  21.             // 发起事件通知  
  22.             fireLifecycleEvent(lifecycleEvent, data);  
  23.         }  
  24.     }  
  25.   
  26.     // 调用LifecycleSupport进行事件处理  
  27.     protected void fireLifecycleEvent(String type, Object data) {  
  28.         lifecycle.fireLifecycleEvent(type, data);  
  29.     }  
  30. }  


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

Java代码  技术分享图片
  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.   
  9. }  



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. 定义实际观察者,按事件来源和类型分别做业务处理,比如投诉创建时,将投诉发生时用户的业务开通快照记录下来。 

 

本文转自:http://learnworld.iteye.com/blog/1013751






































































以上是关于tomcat学习系列---tomcat事件处理机制的主要内容,如果未能解决你的问题,请参考以下文章

tomcat学习笔记Tomcat源码剖析

tomcat学习笔记Tomcat类加载机制

tomcat学习笔记Tomcat类加载机制

tomcat学习

Tomcat系列——Tomcat处理一个HTTP请求的过程

Tomcat源码解读系列——server.xml文件的配置