How tomcat works——6 生命周期

概述

Catalina 由多个组件组成,当 Catalina 启动时,这些组件也需要很好地启动。当Catalina 停止时,这些组件也必须有机会被清除。例如,当一个容器停止工作时,它必须调用所有已加载 servlet 的 destroy()方法,而 session 管理器要把session保存到二级存储中。保持组件启动和停止一致的机制是通过实现org.apache.catalina.Lifecycle 接口来实现的。

一个实现了 Lifecycle 接口的组件会触发一个或多个下列事件:BEFORE_START_EVENT,START_EVENT,AFTER_START_EVENT,BEFORE_STOP_EVENT,STOP_EVENT和AFTER_STOP_EVENT。当组件被启动时前3个事件会被触发,而组件停止时会触发后边3个事件。一个事件是通过org.apache.catalina.LifecycleEvent类来表示。另外,如果一个组件可以触发事件,那么必须存在相应的监听器来对触发的事件作出响应。监听器是通过org.apache.catalina.LifecycleListener接口来表示。

本章会对 Lifecycle, LifecycleEvent和LifecycleListener 进行讨论。另外,还会解释一个公用类 LifecycleSupport——它给组件提供了一个简单方式来触发生命周期事件和处理生命周期监听器。在本章,我们会建立一个有实现了Lifecycle 接口的类的工程。该程序基于第5章应用程序。

6.1 Lifecycle接口

Catalina 的设计允许一个组件可以包含其它组件。例如一个容器可以包含一系列的组件如加载器、管理器等。父组件负责启动和停止其子组件。Catalina被设计成所有的组件仅被一个父组件来监护管理,所以启动 bootstrap类只需启动一个组件即可。这种单一的启动停止机制是通过继承 Lifecycle 来实现。

看 Listing6.1 所示的 Lifecycle 接口:

Listing 6.1: Lifecycle 接口

package org.apache.catalina;

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

Lifecycle 中最重要的方法是 start() 和 stop() 方法。一个组件提供了这些方法的实现,所以它的父组件可以通过这些方法来启动和停止它们。另外 3 个方法addLifecycleListener(), findLifecycleListeners()和removeLifecycleListener() 是跟监听器相关。组件中可以具有对在该组件中发生的事件感兴趣的监听器。 当事件发生时,将会通知对该事件感兴趣的监听器。可以由Lifecycle实例触发的6个事件的名称在接口中public static final String定义。

6.2 LifecycleEvent类

org.apache.catalina.LifecycleEvent类描绘了一个生命周期事件,如 Listing6.2所示:

Listing 6.2: org.apache.catalinaLifecycleEvent 类

package org.apache.catalina;

import java.util.EventObject;

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

6.3 LifecycleListener接口

org.apache.catalina.LifecycleListener 接口表示生命周期监听器,如Listing6.3 所示:

Listing 6.3: org.apache.catalina.LifecycleListener 接口

package org.apache.catalina;
import java.util.EventObject;

public interface LifecycleListener {
    public void lifecycleEvent(LifecycleEvent event);
}

在这个接口中只有lifecycleEvent()一个方法。 当监听器感兴趣的事件触发时,调用此方法。

6.4 LifecycleSupport类

一个实现了 Lifecycle 接口的组件并且允许监听器注册其“感兴趣”的事件,那么它必须提供跟事件相关的方法代码,方法在 Lifecycle 接口中(addLifecycleListener(),findLifecycleListeners() 和 removeLifecycleListener())。这样该组件就可以将其所有监听器添加到数组或 ArrayList 或者其他相似的对象中。Catalina 提供了一个公用类 org.apache.catalina.util.LifecycleSupport 来简化组件处理监听器和触发生命周期事件。LifecycleSupport 如 Listing6.4 所示:

Listing 6.4: LifecycleSupport 类:

package org.apache.catalina.util;

import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;


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

    }
}

如 Listing 6.4 所示,LifecycleSupport 类存储所有的生命周期监听器到一个数组中,该listenens数组,它初始化时没有任何成员:

private LifecycleListener listeners[] = new LifecycleListener[0];

当一个监听器通过 addLifecycleListener()方法被添加时,一个新数组(长度比旧数组大 1)会被创建。然后旧数组中的元素会被拷贝到新数组中并把新事件添加到数组中。当一个事件被删除时,一个新的数组(长度为旧数组-1)会被创建并将所有的元素存储到其中。

fireLifecycleEvent()方法触发一个生命周期事件。首先,它会克隆整个监听器数组,然后它调用每个成员的 lifecycleEvent()方法,传递被触发的事件。

一个实现了 Lifecycle 的组件可以使用 LifecycleSupport 类。例如,该程序的SimpleContext 类声明了如下变量:

protected LifecycleSupport lifecycle = new LifecycleSupport(this);

SimpleContext调用LifecycleSupport 的addLifecycleListener()方法添加一个生命周期事件:

public void addLifecycleListener(LifecycleListener listener) {
    lifecycle.addLifecycleListener(listener);
}

要删除一个生命周期监听事件,SimpleContext 调用 LifecycleSupport 类的removeLifecycleListener()方法:

public void removeLifecycleListener(LifecycleListener listener) {
    lifecycle.removeLifecycleListener(listener);
}

要触发一个事件,SimpleContext 需要调用 LifecycleSupport 的fireLifecycleEvent()方法:

lifecycle.fireLifecycleEvent(START_EVENT, null);

6.5 应用Demo

本章应用Demo构建在第5章的程序之上,用来说明 Lifecycle 接口以及与生命周期相关的其它类型的使用。它包括一个上下文(context)和两个包装器(wrapper)以及一个加载器(loader)和一个映射(mapper)。该应用程序中的组件实现了 Lifecycle 接口,上下文有一个监听器。为了使程序简便,第5章中的2个阀门并没有使用。该程序的结构如图 6.1 所示。注意一些接口(Container, Wrapper, Context, Loader, Mapper)一些类(SimpleContextValve, SimpleContextMapper, and SimpleWrapperValve)并没有出现在该结构图中。
这里写图片描述
图 6.1

注意 SimpleContextLifecycleListener 类表示了 SimpleContext 的监听器。SimpleContextValve, SimpleContextMapper和 SimpleWrapperValve 类跟第5章的程序相同,这里不再讨论。

6.5.1 ex06.pyrmont.core.SimpleContext

该程序中的 SimpleContext 类跟第5章中的相似,不同的是它实现了 Lifecycle接口。SimpleContext 类使用如下变量来引用一个 LifecycleSupport 实例:

protected LifecycleSupport lifecycle = new LifecycleSupport(this);

它还使用一个名为 started 的变量来标记该 SimpleContext 实例是否已经启动。SimpleContext 类实现了 Lifecycle 接口中的方法,这些方法如 Listing6.5 所示:

Listing 6.5: Lifecycle 接口方法实现:

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

注意 start() 方法是如何启动所有子容器以及其相关组件(Loader, Pipeline和Mapper),以及 stop()如何停止这些组件的?使用该机制,可以启动容器模型中所有的组件,我们只需要启动最高层的组件即可(在该例子中指SimpleContext 实例)。而停止它们的时候只需简单停止相同的组件(SimpleContext)即可。

SimpleContext 的 start() 方法首先会检查是否已预先启动,如果已经启动了,则会抛出 LifecycleException 异常。

if (started)
    throw new LifecycleException("SimpleContext has already started");

.
然后它产生了 BEFORE_START_EVENT 事件:

// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);

其结果就是 SimpleContext 实例中注册的监听器都会被唤醒。在该Demo中,一个类型为SimpleContextLifecycleListener的监听器会注册它“感兴趣”的事件。当我们讨论SimpleContextLifecycleListener类时,将会看到此监听器发生了什么事。

接下来,start() 方法设置 started 布尔变量为true来标记该组件已经启动:

started = true;

start() 方法接下来会启动所有组件以及其子容器。现在有2个组件实现了Lifecycle 接口:SimpleLoader 和 SimplePipeline。SimpleContext 有2个包装器作为其子容器。这些包装器也实现了 Lifecycle 接口:

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();

组件和子容器都被启动之后,start() 方法产生START_EVENT 和AFTER_START_EVENT这2个事件:

// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(START_EVENT, null);
....
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);

stop()方法首先检查该实例是否已经启动。如果没有启动则会产生一个LifecycleException 类型异常:

if (!started)
    throw new LifecycleException("SimpleContext has not been started");

接下来会触发 BEFORE_STOP_EVENT 和 STOP_EVENT 事件,并重置 started 变量:

// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
lifecycle.fireLifecycleEvent(STOP_EVENT, null);
started = false;

接下来 stop() 方法会停止所有相关组件以及 SimpleContext 的子容器:

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

最后,产生 AFTER_STOP_EVENT 事件:

// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);

6.5.2 ex06.pyrmont.core. SimpleContextLifecycleListener

SimpleContextLifecycleListener 表示 SimpleContext 实例的监听器。

Listing 6.6: SimpleContextLifecycleListener 类

package ex06.pyrmont.core;

import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;

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.");
    }
  }
}

SimpleContextLifecycleListener 类中 lifecycleEvent()方法的实现很简单。只是打印出触发的类型,如果事件为 START_EVENT 事件,则打印出“Starting context.”,如果事件为 STOP_EVENTT,则打印出“Stopping contex”。

6.5.3 ex06.pyrmont.core. SimpleLoader

SimpleLoader 跟第5章中相似,不同之处在于它实现了 Lifecycle 接口,所实现的方法什么都没做只是打印出一些字符串到控制台上。更重要的是,实现了Lifecycle 接口,一个 SimpleLoader 实例就可以通过其相关容器启动它。

Lifecycle 接口方法实现如 Listing6.7 所示:

Listing 6.7: Lifecycle接口方法在SimpleLoader 实现:

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 SimpleLoader");
}

public void stop() throws LifecycleException { }

6.5.4 ex06.pyrmont.core. SimplePipeline

另外Pipeline接口和SimplePipeline类也实现了Lifecycle接口。从Lifecycle接口继承来的方法被留空。现在这个类的实例可以由其相关容器来启动,该类的其它部分跟第5章中的相似。

6.5.5 ex06.pyrmont.core. SimpleWrapper

该类跟 ex05.pyrmont.core.SimpleWrapper 很相似。在该应用中,它实现了Lifecycle 接口,所以它可以由其父容器来启动。在该程序中除start() 和 stop()方法之外的大多数从 Lifecycle 接口获得的方法被留空。Listing6.8 展示了这些方法的实现:

Listing 6.8: The methods from the Lifecycle interface

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

SimpleWrapper 中的 start() 方法跟 SimpleContext 类中的 start() 方法相似。它启动所有的组件并触发 BEFORE_START_EVENT, START_EVENT和AFTER_START_EVENT 事件。

SimpleWrapper的stop()更有趣,它打印出一个简单的字符串,并调用servlet实例的 destroy() 方法。

System.out.println("Stopping wrapper " + name);
// Shut down our servlet instance (if it has been initialized)
try {
    instance.destroy();
}catch (Throwable t) {}
instance = null;

然后它检查该包装器是否被启动了,如果没有会抛出 LifecycleException:

if (!started)
    throw new LifecycleException("Wrapper " + name + " not started");

接下来,它触发 BEFORE_STOP_EVENT 和 STOP_EVENT 事件并重置 started 布尔变量:

// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(STOP_EVENT, null);
started = false;

接下来它停止跟其相关的管道组件(pipeline)和加载器(loader)。在该应用程序中,SimpleWrapper实例没有加载器。

// 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();
}

最后,它触发了 AFTER_STOP_EVENT 事件:

// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);

6.5.6 运行Demo

在 windows 下,可以在工作目录下面如下运行该程序:

java -classpath ./lib/servlet.jar;./ ex06.pyrmont.startup.Bootstrap

在 Linux 下,使用冒号分开两个库:

java -classpath ./lib/servlet.jar:./ ex06.pyrmont.startup.Bootstrap

我们可在控制台看到如下信息。注意有哪些事件被触发?

HttpConnector Opening server socket on all host IP addresses
HttpConnector[8080] Starting background thread
SimpleContextLifecycleListener's event before_start
Starting SimpleLoader
Starting Wrapper Modern
Starting Wrapper Primitive
SimpleContextLifecycleListener's event start
Starting context.
SimpleContextLifecycleListener's event after_start

调用PrimitiveServlet,可以使用下面的 URL 来请求:

http://localhost:8080/Primitive

调用ModernServlet,可以使用下面的 URL 来请求:

http://localhost:8080/Modern

6.6 小结

在本章中,我们学习了如何使用Lifecycle接口。 这个接口定义了组件的生命周期,并提供了一种优雅方式发送事件到其它组件。 此外,Lifecycle接口也实现了可以通过一个单独的start()/stop()来启动和停止Catalina中的所有组件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值