tomcat生命周期的管理——生命周期统一接口Lifecycle

时间:2022-02-22 08:59:03

我们知道Tomcat的架构设计是清晰的、模块化的,其拥有很多组件,假如我们要启动Tomcat,可以一个一个启动组件,但这样启动有很多缺点,不仅麻烦,而且容易漏了组件启动,还会对后面动态组件扩展带来麻烦。难不成真要我们一个一个启动吗?其实未必,Tomcat的设计者提供了一个解决方案:用Lifecycle管理启动、停止、关闭。

从第一节的架构图可以看到各个核心组件有包含与被包含的关系,例如Server<-Service<-ContainerConnector,最大的是Server,往下一层层包含。其实Tomcat就是以容器的方式来组织整个系统架构的,反映到数据结构就是树,树的根节点没有父节点,其它节点有且仅有一个父节点,每个父节点有零个或多个子节点,根容器与其他容器也有这样的特点。鉴于如此,可以通过父容器负责启动它的子容器,这样只要启动根容器,即可把其他所有容器都启动,达到统一启动、停止、关闭的效果。

Lifecycle作为统一的接口,把所有的启动、停止、关闭、生命周期相关方法都组织到一起,就可以很方便地管理Tomcat各个容器组件的生命周期。下面是Lifecycle接口详细的定义:

public interface 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";

   

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

   public String getStateName();

}

从上面可以看出Lifecycle其实就是定义了一些状态常量跟几个方法,这里主要看下initstartstop三个方法,所有需要被生命周期管理的容器都要实现这个接口,并且各自被父容器的相应方法调用,例如在初始化阶段,根容器Server会调用init方法,而在init方法里会调用它的子容器Serviceinit方法,以此类推。

在实际使用中,一般只有统一实现Lifecycle接口后才能实现统一调用,例如调用容器的init方法是这样子:((Lifecycle)容器).init()。下面简单看看Tomcat源码的Server是怎样调用init的。

 

publicfinalsynchronizedvoid init()throws LifecycleException {

……

for (int i = 0; i < services.length; i++) {

           services[i].init();

       }

 ……

}

 

Server容器里面有若干多个Service实例,那么只要用一个for循环即可分别让每个Service调用init方法。这里的services[i]并没有用(Lifecycle)显式转换类型,其实是因为Service也是一个接口,而这个接口已经继承了Lifecycle接口。

同样的,启动跟停止步骤也是通过类似的调用实现统一启动统一关闭。至此,我们对Tomcat的生命周期统一初始化、启动、关闭机制有了比较清晰的认识。


点击订购作者《Tomcat内核设计剖析》