本文接下来描述servlet容器是怎样管理其相关组件的生命周期的,首先本人描述一下事件监听模式,也可以称为观察者模式,该模式分为以下角色

即抽象主题角色 具体主题角色 抽象观察者角色及具体观察者角色,通常在主题角色里面维持一个观察者角色的聚集,并定义了对观察者角色的添加和删除方法;在主题角色事件发生时,通过迭代向这些观察者角色发布事件。

在tomcat容器中,管理其相关组件的生命周期即是基于事件监听模式实现的,相关接口和类为org.apache.catalina.Lifecycle接口、org.apache.catalina.LifecycleListener接口、org.apache.catalina.LifecycleEvent类

org.apache.catalina.Lifecycle接口定义如下

public interface Lifecycle {

    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 void addLifecycleListener(LifecycleListener listener);

    public LifecycleListener[] findLifecycleListeners();

    public void removeLifecycleListener(LifecycleListener listener);

    public void start() throws LifecycleException;

    public void stop() throws LifecycleException;

}

上面的六个静态字符串代表六种类型的事件,接着的三个方法addLifecycleListener()、 findLifecycleListeners()、removeLifecycleListener()为与事件监听器相关的,最后的两个方法start()和stop()为启动与关闭操作,组件必须提供这两种方法的实现,供其父组件调用。

org.apache.catalina.LifecycleEvent类用于传递事件及携带事件数据

public final class LifecycleEvent
extends EventObject { public LifecycleEvent(Lifecycle lifecycle, String type) {
this(lifecycle, type, null);
} public LifecycleEvent(Lifecycle lifecycle, String type, Object data) { super(lifecycle);
this.lifecycle = lifecycle;
this.type = type;
this.data = data;
} private Object data = null; private Lifecycle lifecycle = null; private String type = null; public Object getData() {
return (this.data);
} public Lifecycle getLifecycle() {
return (this.lifecycle);
} public String getType() {
return (this.type);
}
}

org.apache.catalina.LifecycleListener为监听器接口

public interface LifecycleListener {

    /**
* Acknowledge the occurrence of the specified event.
*
* @param event LifecycleEvent that has occurred
*/
public void lifecycleEvent(LifecycleEvent event); }

通常实现了Lifecycle接口并且对某个事件注册了监听器的组件必须提供 Lifecycle接口中三个与监听器相关方法(分别为addLifecycleListener()、 findLifecycleListeners()、removeLifecycleListener())的实现,然后该组件需要将所有注册的监听器存储到数组、ArrayList或者其他类似的对象中;tomcat容器提供了一个工具类org.apache.catalina.util.LifecycleSupport来帮助组件管理监听器,并触发相应的生命周期事件。

public final class LifecycleSupport {

    public LifecycleSupport(Lifecycle lifecycle) {

        super();
this.lifecycle = lifecycle; } private Lifecycle lifecycle = null; private LifecycleListener listeners[] = new LifecycleListener[0]; public void addLifecycleListener(LifecycleListener listener) { synchronized (listeners) {
LifecycleListener results[] =
new LifecycleListener[listeners.length + 1];
for (int i = 0; i < listeners.length; i++)
results[i] = listeners[i];
results[listeners.length] = listener;
listeners = results;
} } public LifecycleListener[] findLifecycleListeners() { return listeners; } public void fireLifecycleEvent(String type, Object data) { LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
LifecycleListener interested[] = null;
synchronized (listeners) {
interested = (LifecycleListener[]) listeners.clone();
}
for (int i = 0; i < interested.length; i++)
interested[i].lifecycleEvent(event); } public void removeLifecycleListener(LifecycleListener listener) { synchronized (listeners) {
int n = -1;
for (int i = 0; i < listeners.length; i++) {
if (listeners[i] == listener) {
n = i;
break;
}
}
if (n < 0)
return;
LifecycleListener results[] =
new LifecycleListener[listeners.length - 1];
int j = 0;
for (int i = 0; i < listeners.length; i++) {
if (i != n)
results[j++] = listeners[i];
}
listeners = results;
}
}
}

下面我们来看Context容器(SimpleContext实例)是怎么实现生命周期管理及触发监听器事件的,关键代码如下

public class SimpleContext implements Context, Pipeline, Lifecycle {

protected LifecycleSupport lifecycle = new LifecycleSupport(this);

// implementation of the Lifecycle interface's methods
public void addLifecycleListener(LifecycleListener listener) {
lifecycle.addLifecycleListener(listener);
} public LifecycleListener[] findLifecycleListeners() {
return null;
} public void removeLifecycleListener(LifecycleListener listener) {
lifecycle.removeLifecycleListener(listener);
} public synchronized void start() throws LifecycleException {
if (started)
throw new LifecycleException("SimpleContext has already started"); // Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
started = true;
try {
// Start our subordinate components, if any
if ((loader != null) && (loader instanceof Lifecycle))
((Lifecycle) loader).start(); // Start our child containers, if any
Container children[] = findChildren();
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof Lifecycle)
((Lifecycle) children[i]).start();
} // Start the Valves in our pipeline (including the basic),
// if any
if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start();
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(START_EVENT, null);
}
catch (Exception e) {
e.printStackTrace();
} // Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
} public void stop() throws LifecycleException {
if (!started)
throw new LifecycleException("SimpleContext has not been started");
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
lifecycle.fireLifecycleEvent(STOP_EVENT, null);
started = false;
try {
// Stop the Valves in our pipeline (including the basic), if any
if (pipeline instanceof Lifecycle) {
((Lifecycle) pipeline).stop();
} // Stop our child containers, if any
Container children[] = findChildren();
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof Lifecycle)
((Lifecycle) children[i]).stop();
}
if ((loader != null) && (loader instanceof Lifecycle)) {
((Lifecycle) loader).stop();
}
}
catch (Exception e) {
e.printStackTrace();
}
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
}
}

Context容器实例持有对LifecycleSupport lifecycle = new LifecycleSupport(this)的引用,与事件监听器相关方法均为操作该实例的相应方法

在其与生命周期相关方法start()和stop()方法里面,分别调用相关组件的生命周期方法,并采用LifecycleSupport lifecycle引用发布事件

一个简单的监听器实现如下:

public class SimpleContextLifecycleListener implements LifecycleListener {

  public void lifecycleEvent(LifecycleEvent event) {
Lifecycle lifecycle = event.getLifecycle();
System.out.println("SimpleContextLifecycleListener's event " +
event.getType().toString());
if (Lifecycle.START_EVENT.equals(event.getType())) {
System.out.println("Starting context.");
}
else if (Lifecycle.STOP_EVENT.equals(event.getType())) {
System.out.println("Stopping context.");
}
}
}

子容器wrapper实例(SimpleWrapper),同样实现了Lifecycle接口,其相关实现与Context容器类似

public class SimpleWrapper implements Wrapper, Pipeline, Lifecycle {

protected LifecycleSupport lifecycle = new LifecycleSupport(this);

// implementation of the Lifecycle interface's methods
public void addLifecycleListener(LifecycleListener listener) {
} public LifecycleListener[] findLifecycleListeners() {
return null;
} public void removeLifecycleListener(LifecycleListener listener) {
} public synchronized void start() throws LifecycleException {
System.out.println("Starting Wrapper " + name);
if (started)
throw new LifecycleException("Wrapper already started"); // Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
started = true; // Start our subordinate components, if any
if ((loader != null) && (loader instanceof Lifecycle))
((Lifecycle) loader).start(); // Start the Valves in our pipeline (including the basic), if any
if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start(); // Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(START_EVENT, null);
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
} public void stop() throws LifecycleException {
System.out.println("Stopping wrapper " + name);
// Shut down our servlet instance (if it has been initialized)
try {
instance.destroy();
}
catch (Throwable t) {
}
instance = null;
if (!started)
throw new LifecycleException("Wrapper " + name + " not started");
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null); // Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(STOP_EVENT, null);
started = false; // Stop the Valves in our pipeline (including the basic), if any
if (pipeline instanceof Lifecycle) {
((Lifecycle) pipeline).stop();
} // Stop our subordinate components, if any
if ((loader != null) && (loader instanceof Lifecycle)) {
((Lifecycle) loader).stop();
} // Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
}
}

其他相关组件的相关实现不再赘述

---------------------------------------------------------------------------

本系列How Tomcat Works系本人原创

转载请注明出处 博客园 刺猬的温驯

本人邮箱: chenying998179#163.com (#改为@)

本文链接http://www.cnblogs.com/chenying99/p/3235736.html

How Tomcat Works(九)的更多相关文章

  1. How Tomcat Works(十九)

    本文重点关注启动tomcat时会用到的两个类,分别为Catalina类和Bootstrap类,它们都位于org.apachae.catalina.startup包下:Catalina类用于启动或关闭S ...

  2. 攻城狮在路上(肆)How tomcat works(零) 前言说明

    最近几篇是关于How tomcat works一书的读书笔记. 通过数个章节逐渐实现一个tomcat的功能. 源码下载地址:http://zhidao.baidu.com/share/7007af0f ...

  3. How Tomcat works — 四、tomcat启动(3)

    上一节说到StandardService负责启动其子组件:container和connector,不过注意,是有先后顺序的,先启动container,再启动connector,这一节先来看看conta ...

  4. How Tomcat Works(十四)补充

    在How Tomcat Works(十四)中,本人并没有对javax.servlet.Filter及javax.servlet.FilterChain做详细的描述,本文在这里做一下补充 FilterC ...

  5. How Tomcat Works(十八)

    在前面的文章中,如果我们要启动tomcat容器,我们需要使用Bootstrap类来实例化连接器.servlet容器.Wrapper实例和其他组件,然后调用各个对象的set方法将它们关联起来:这种配置应 ...

  6. How Tomcat Works(十七)

    在前面的文章中,已经学会了如何通过实例化一个连接器和容器来获得一个servlet容器,并将连接器和容器相关联:但在前面的文章中只有一个连接器可用,该连接器服务8080端口上的HTTP请求,无法添加另一 ...

  7. How Tomcat Works(十六)

    本文接下来会介绍Host容器和Engine容器,在tomcat的实际部署中,总是会使用一个Host容器:本文介绍Host接口和Engine接口及其相关类 Host容器是org.apache.catal ...

  8. How Tomcat Works(十五)

    本文接下来分析Context容器,Context容器实例表示一个具体的Web应用程序,其中包括一个或多个Wrapper实例:不过Context容器还需要其他的组件支持,典型的如载入器和Session管 ...

  9. How Tomcat Works(十四)

    我们已经知道,在tomcat中有四种类型的servlet容器,分别为Engine.Host.Context 和Wrapper,本文接下来对tomcat中Wrapper接口的标准实现进行说明. 对于每个 ...

随机推荐

  1. LA 3516 Exploring Pyramids (记忆化搜索)

    题意 给定一个DFS序列,问能有多少树与之对应. 思路 设输入序列为S,dp(i, j)为子序列Si, Si+1, --, Sj对应的树的个数,则边界条件为d(i, i) = 1,且Si != Sj时 ...

  2. 移植yaffs文件系统

    需要下载yaffs2-d43e901.tar.gz,busybox-1.13.0.tar.bz2 使用的交叉编译器是4.33 1.修改配置编译busybox 修改Makefile CROSS_COMP ...

  3. 利用android proguard混淆代码

    利用android proguard混淆代码 2014-02-05 17:50 1207人阅读 评论(1) 收藏 举报 网上虽然有很多相关博客,不过貌似都不是最新版的..于是百度+谷歌+github上 ...

  4. JVM——类加载器的双亲委派模型

    类加载器双亲委派模型,如下图所示: 双亲委派模型的工作过程 如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此 ...

  5. 解析AFNetWorking 网络框架(二)

    转:http://blog.csdn.net/andy_jiangbin/article/details/17114989 接着前面写. 本帖先讲AFURLConnectionOperation,它是 ...

  6. SVN 命令行 精编版

    1.将文件checkout到本地目录 svn checkout path(path是服务器上的目录) 例如:svn checkout https://svn.sinaapp.com/beckhom 简 ...

  7. 15stl模板

    1.stack #include<iostream> #include<stdio.h> #include<stack> using namespace std; ...

  8. Solution multisite htaccess cleanURL

    My solution to getting Clean URL working with my multisite setup drupal 4.7 I added Alias to my http ...

  9. jquery小技巧汇总 持续更新中

    1.jquery高亮当前选中菜单 $("document").ready(function(){ $(".menu li").click(function(){ ...

  10. 单独删除std::vector <std::vector<string> > 的所有元素

    下面为测试代码: 1.创建 std::vector< std::vector<string> > vc2; 2.初始化 std::vector<string> vc ...