Tomcat源码分析之生命周期管理

Tomcat源码调试环境搭好了,但是打开源码却是一头雾水,不知从哪下手,我觉得这是阅读任何项目源码刚开始都会遇到的问题,但是问题从来不可怕,下面我在Tomcat源码分析中的一些理解吧。

概念理解

谈一下对「容器」、「生命周期」、「观察者模式」这个三个概念的理解,这几个是介绍Tomcat源码和系统架构的书籍和文章中常见的概念,也是理解Tomcat设计的精髓。

  • 容器
    打开源码“/conf”目录下的server.xml文件,可以看到最顶层到里面依次有server、service、connector等等,这些解析之后便成为Tomcat的容器。我们姑且可以理解为管理子容器或者内部一些未知东西的工具。
  • 生命周期
    容器有初始化(init)、开始(start)和停止(stop)等各种状态,如何去管理一个容器从开始到结束,这应该就是生命周期管理吧,先这么简单的理解吧,认识都是一个过程,暂时也没法理解的那么全面。
  • 观察者模式
    不太理解的可以专门看看这个设计模式。这里可以简单理解为,把容器当做一个主题(subject),还有若干监听者(listener),容器状态的改变会触发监听者listener的一些动作等等。

关键类和接口

  • Bootstrap
    Tomcat源码工程巨大,但是总有一个入口,我们在启动Tomcat工程的时候,会发现项目是从Bootstrap类开始(org.apache.catalina.startup.Bootstrap.java),main方法就在这里了,到此至少知道项目是从何处开始的了。
  • StandardServer
    该类是对Server的具体实现,Tomcat的生命周期就是由Server掌控,Server由此是Tomcat最高级的组件,没有之一,Tomcat启动之后,首先便是Server的启动。至于Server下面的service容器暂时先不管,知道了一种容器的生命周期,其他的也就类似了。
  • LifecycleBase
    该类是对Lifecycle接口的实现,所有的容器都是要继承该类的,StandardServer的继承关系是:StandardServer-LifecycleMBeanBase-LifecycleBase。
  • LifecycleSupport
    是LifecycleBase的一个支持辅助类吧,随着容器的新建会初始化new一个,容器状态如果改变,会帮忙搞定事件触发的操作。
  • LifecycleListener
    上面的三个类主要跟容器有关,而这是一个监听者接口,看下面源码中的注释就可以知道了这个接口的作用的,下面是完整接口:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    /**
    * Interface defining a listener for significant events (including "component
    * start" and "component stop" generated by a component that implements the
    * Lifecycle interface. The listener will be fired after the associated state
    * change has taken place.
    *
    * @author Craig R. McClanahan
    */
    public interface LifecycleListener {
    /**
    * Acknowledge the occurrence of the specified event.
    *
    * @param event LifecycleEvent that has occurred
    */
    public void lifecycleEvent(LifecycleEvent event);
    }

翻译一下:接口定义了一个对一些重要events感兴趣的listener,主要是那些由实现了Lifecycle接口的组件所产生的包括“start”和“stop”的events事件,这个监听者会被关联的状态触发。

生命周期管理及观察流程

StandardServer的startInternal()开始

StandardServer父类LifecycleBase中的start()方法被调用之后,紧接着StandardServer的startInternal()调用,下面是startInternal()的具体实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected void startInternal() throws LifecycleException {
fireLifecycleEvent(CONFIGURE_START_EVENT, null);//容器启动,触发事件
setState(LifecycleState.STARTING);//设置容器的状态为STARTING
globalNamingResources.start();
// Start our defined Services
synchronized (servicesLock) {
for (int i = 0; i < services.length; i++) {
services[i].start();
}
}
}

LifecycleBase的fireLifecycleEvent()方法代理

因为我自己状态改变了下,我要把消息告诉那些监听者,StandardServer调用了父类LifecycleBase的fireLifecycleEvent(),该方法代码如下:

1
2
3
4
5
6
7
/**
* @param type Event type
* @param data Data associated with event.
*/
protected void fireLifecycleEvent(String type, Object data) {
lifecycle.fireLifecycleEvent(type, data);
}

lifecycle是这么被定义的:

1
2
3
4
5
/**
* Used to handle firing lifecycle events.
* TODO: Consider merging LifecycleSupport into this class.
*/
private LifecycleSupport lifecycle = new LifecycleSupport(this);

思考弄一下这里的this参数是什么,说白了LifecycleSupport就是专门定义一个帮忙干活的,this就是当前的容器实例。

LifecycleSupport的fireLifecycleEvent()方法被触发

直接上代码吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* Notify all lifecycle event listeners that a particular event has
* occurred for this Container. The default implementation performs
* this notification synchronously using the calling thread.
*
* @param type Event type
* @param data Event data
*/
public void fireLifecycleEvent(String type, Object data) {
LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
LifecycleListener interested[] = listeners;
for (int i = 0; i < interested.length; i++)
interested[i].lifecycleEvent(event);
}

问题已经快水落石出了,LifecycleSupport似乎是维护了listener的一个数据结构,数组,如下代码所示:

1
2
3
4
/**
* The set of registered LifecycleListeners for event notifications.
*/
private LifecycleListener listeners[] = new LifecycleListener[0];

LifecycleSupport专门负责管理一些监听者(listener)的事情,比如:addLifecycleListener()、removeLifecycleListener()等等,跟listeners打交道的脏活累活最后都落到LifecycleSupport身上了。

LifecycleListener的lifecycleEvent()方法被触发

因为LifecycleListener只是一个接口,所以举一个实现类为例,如NamingContextListener类,为什么拿这个举例后面就知道了,下面就是NamingContextListener的lifecycleEvent(LifecycleEvent event)方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* Acknowledge the occurrence of the specified event.
*
* @param event LifecycleEvent that has occurred
*/
@Override
public void lifecycleEvent(LifecycleEvent event) {
....//略
if (Lifecycle.CONFIGURE_START_EVENT.equals(event.getType())) {
....
} else if (Lifecycle.CONFIGURE_STOP_EVENT.equals(event.getType())) {
if (!initialized)
return;
try {
...
} finally {
objectNames.clear();
namingContext = null;
envCtx = null;
compCtx = null;
initialized = false;
}
}
}

代码太长不贴那么多了,但是窥一斑可知,这里面做了很多事情,根据事件不同给出不同的处理。那么这个监听器是什么时候加入监听数组的呢?

LifecycleListener的加入

因为我们一开始就只讨论Server这个容器,那么回到刚开始的Server的实现类StandardServer这个类,观察构造方法会发现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* Construct a default instance of this class.
*/
public StandardServer() {
super();
globalNamingResources = new NamingResources();
globalNamingResources.setContainer(this);
if (isUseNaming()) {
namingContextListener = new NamingContextListener();
addLifecycleListener(namingContextListener);
}
}

NamingContextListener这个listener是在容器创建之初就被放入了监听者行列,addLifecycleListener方法便是调用LifecycleBase的addLifecycleListener()这个代理方法,然后真正的脏活累活还是交给了前面交代的LifecycleSupport这个类来办。

最后

容器的生命周期和观察者模式大概就是这么回事了,后面还有一些问题需要继续思考,比如Server下面的Service到底是什么东西,Service里面的connector和container又是什么鬼,再慢慢分析吧。

-EOF-