Tomcat7启动分析(五)Lifecycle机制和实现原理

在上篇文章分析Tomcat7的各组件的init、start方法时经常会看到有一个setStateInternal方法的调用,在查看LifecycleBase类及其它各组件的源码时会在多处看到这个方法的调用,这篇文章就来说说这方法,以及与这个方法相关的Tomcat的Lifecycle机制和实现原理。

 

上篇文章里谈到Tomcat7的各组件的父类LifecycleBase类,该类实现了接口org.apache.catalina.Lifecycle,下面是这个接口里定义的常量和方法:

细心的读者会发现,上篇文章里提到的init和start方法实际上是在这个接口里面定义好的,也正因为有各组件最终都会实现这个接口作为前提条件,所以才能支持组件内部的initInternal、startInternal方法内对于子组件(组件里面嵌套的子组件都是以接口的形式定义的,但这些接口都会以Lifecycle作为父接口)的init和start方法的调用。通过这种方式,只要调用了最外层的Server组件的init和start方法,就可以将Tomcat内部的各级子组件初始化和启动起来。我叫这种方式为链式调用。实际上关于Tomcat的关闭机制也是通过这种方式一步步调用各层组件的stop方法的。这里不再展开叙述,留待读者自己研究研究吧。眨眼

 

Lifecycle接口中的这些字符串常量定义主要用于事件类型的定义,先按下不表,文章后面会提到。

 

重点看下面三个方法:

 1     /**
 2      * Add a LifecycleEvent listener to this component.
 3      *
 4      * @param listener The listener to add
 5      */
 6     public void addLifecycleListener(LifecycleListener listener);//给该组将添加一个监听器
 7 
 8 
 9     /**
10      * Get the life cycle listeners associated with this life cycle. If this
11      * component has no listeners registered, a zero-length array is returned.
12      */
13     public LifecycleListener[] findLifecycleListeners();//获取该组件所有已注册的监听器
14 
15 
16     /**
17      * Remove a LifecycleEvent listener from this component.
18      *
19      * @param listener The listener to remove
20      */
21     public void removeLifecycleListener(LifecycleListener listener);//删除该组件中的一个监听器

这三个方法的作用在代码的注释里简要说明了一下。这三个方法涉及org.apache.catalina.LifecycleListener接口,那么就看下这个接口的定义:

 1 public interface LifecycleListener {
 2 
 3 
 4     /**
 5      * Acknowledge the occurrence of the specified event.
 6      *
 7      * @param event LifecycleEvent that has occurred
 8      */
 9     public void lifecycleEvent(LifecycleEvent event);
10 
11 
12 }

如此简单,只有一个方法,这个方法用作某个事件(org.apache.catalina.LifecycleEvent)产生时通知当前监听器的实现类,具体针对该事件如何处理由监听器实现类自己决定。

 

看下LifecycleEvent的实现:

 1 public final class LifecycleEvent extends EventObject {
 2 
 3     private static final long serialVersionUID = 1L;
 4 
 5 
 6     // ----------------------------------------------------------- Constructors
 7 
 8     /**
 9      * Construct a new LifecycleEvent with the specified parameters.
10      *
11      * @param lifecycle Component on which this event occurred
12      * @param type Event type (required)
13      * @param data Event data (if any)
14      */
15     public LifecycleEvent(Lifecycle lifecycle, String type, Object data) {
16 
17         super(lifecycle);
18         this.type = type;
19         this.data = data;
20     }
21 
22 
23     // ----------------------------------------------------- Instance Variables
24 
25 
26     /**
27      * The event data associated with this event.
28      */
29     private Object data = null;
30 
31 
32     /**
33      * The event type this instance represents.
34      */
35     private String type = null;
36 
37 
38     // ------------------------------------------------------------- Properties
39 
40 
41     /**
42      * Return the event data of this event.
43      */
44     public Object getData() {
45 
46         return (this.data);
47 
48     }
49 
50 
51     /**
52      * Return the Lifecycle on which this event occurred.
53      */
54     public Lifecycle getLifecycle() {
55 
56         return (Lifecycle) getSource();
57 
58     }
59 
60 
61     /**
62      * Return the event type of this event.
63      */
64     public String getType() {
65 
66         return (this.type);
67 
68     }
69 
70 
71 }

这个类也很简单,data和type作为类的内置实例变量,唯一特别是使用了jdk内置的java.util.EventObject作为父类来支持事件定义,这里在事件构造函数中将org.apache.catalina.Lifecycle类的实例lifecycle作为事件源,保存lifecycle对象的引用,并提供了getLifecycle方法返回这个引用。

 

那么Tomcat中是如何实现关于这些事件的监听以及通知的呢?

 

在本文开头提到的LifecycleBase类中第47行定义了一个实例变量lifecycle,正是通过该变量来注册组件上定义的各类监听器的。留心一下lifecycle这个实例变量,它并不是org.apache.catalina.Lifecycle类的实例,而是org.apache.catalina.util.LifecycleSupport类的实例。正是这个工具类提供了事件监听和事件通知的功能。

 

先看下实际代码中是如何给组件发布时间通知的,看下前面文章中曾经提到过的org.apache.catalina.core.StandardServer类的startInternal方法:

 1     protected void startInternal() throws LifecycleException {
 2 
 3         fireLifecycleEvent(CONFIGURE_START_EVENT, null);
 4         setState(LifecycleState.STARTING);
 5 
 6         globalNamingResources.start();
 7         
 8         // Start our defined Services
 9         synchronized (services) {
10             for (int i = 0; i < services.length; i++) {
11                 services[i].start();
12             }
13         }
14     }

我们前面已经分析过第9到13行代码,这里看下第3行,它调用了父类org.apache.catalina.util.LifecycleBase里的fireLifecycleEvent方法,这里的CONFIGURE_START_EVENT就是本文最开始Lifecycle接口中定义的常量,这里表示发布了一个start配置事件。

 

org.apache.catalina.util.LifecycleBase类中的fireLifecycleEvent方法里调用的是org.apache.catalina.util.LifecycleSupport类fireLifecycleEvent方法,该方法代码如下:

1     public void fireLifecycleEvent(String type, Object data) {
2 
3         LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
4         LifecycleListener interested[] = listeners;
5         for (int i = 0; i < interested.length; i++)
6             interested[i].lifecycleEvent(event);
7 
8     }

这里通过传进来的两个参数构造一个LifecycleEvent对象,然后向注册到组件中的所有监听器发布这个新构造的事件对象。

 

这里有个疑问,到底什么时候向组件里注册监听器的呢?

 

还是以StandardServer举例,在前面讲Digester的使用时,org.apache.catalina.startup.Catalina类的createStartDigester方法有这么一段代码:

 1         // Configure the actions we will be using
 2         digester.addObjectCreate("Server",
 3                                  "org.apache.catalina.core.StandardServer",
 4                                  "className");
 5         digester.addSetProperties("Server");
 6         digester.addSetNext("Server",
 7                             "setServer",
 8                             "org.apache.catalina.Server");
 9 
10         digester.addObjectCreate("Server/GlobalNamingResources",
11                                  "org.apache.catalina.deploy.NamingResources");
12         digester.addSetProperties("Server/GlobalNamingResources");
13         digester.addSetNext("Server/GlobalNamingResources",
14                             "setGlobalNamingResources",
15                             "org.apache.catalina.deploy.NamingResources");
16 
17         digester.addObjectCreate("Server/Listener",
18                                  null, // MUST be specified in the element
19                                  "className");
20         digester.addSetProperties("Server/Listener");
21         digester.addSetNext("Server/Listener",
22                             "addLifecycleListener",
23                             "org.apache.catalina.LifecycleListener");

第17到24行,将调用org.apache.catalina.core.StandardServer类的addLifecycleListener方法,将根据server.xml中配置的Server节点下的Listener节点所定义的className属性构造对象实例,并作为addLifecycleListener方法的入参。所有的监听器都会实现上面提到的org.apache.catalina.LifecycleListener接口。Server节点下的Listener节点有好几个,这里以org.apache.catalina.core.JasperListener举例。

 

在构造完org.apache.catalina.core.JasperListener类的对象之后,调用addLifecycleListener方法,这个方法并没有直接在org.apache.catalina.core.StandardServer类中定义,而是在它的父类org.apache.catalina.util.LifecycleBase中:

1     @Override
2     public void addLifecycleListener(LifecycleListener listener) {
3         lifecycle.addLifecycleListener(listener);
4     }

这里调用的是前述的org.apache.catalina.util.LifecycleSupport类的addLifecycleListener方法:

 1     /**
 2      * Add a lifecycle event listener to this component.
 3      *
 4      * @param listener The listener to add
 5      */
 6     public void addLifecycleListener(LifecycleListener listener) {
 7 
 8       synchronized (listenersLock) {
 9           LifecycleListener results[] =
10             new LifecycleListener[listeners.length + 1];
11           for (int i = 0; i < listeners.length; i++)
12               results[i] = listeners[i];
13           results[listeners.length] = listener;
14           listeners = results;
15       }
16 
17     }

LifecycleSupport作为一个工具类,内部保存了一个监听器对象实例数组,见该类的第68行:

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

上面的addLifecycleListener方法内部实现的是同步给该数组增加一个监听器对象。

 

看到这里应该大体明白Tomcat中的Lifecycle是怎么回事了,总的来说就是通过一个工具类LifecycleSupport,调用该类的addLifecycleListener方法增加监听器,需要发布事件时还是调用该工具类的fireLifecycleEvent方法,将事件发布给组件上注册的所有监听器,由监听器内部实现来决定是否处理该事件。

 

以前面看到的一个监听器org.apache.catalina.core.JasperListener举例:

 1 public class JasperListener
 2     implements LifecycleListener {
 3 
 4     private static final Log log = LogFactory.getLog(JasperListener.class);
 5 
 6     /**
 7      * The string manager for this package.
 8      */
 9     protected static final StringManager sm =
10         StringManager.getManager(Constants.Package);
11 
12 
13     // ---------------------------------------------- LifecycleListener Methods
14 
15 
16     /**
17      * Primary entry point for startup and shutdown events.
18      *
19      * @param event The event that has occurred
20      */
21     @Override
22     public void lifecycleEvent(LifecycleEvent event) {
23 
24         if (Lifecycle.BEFORE_INIT_EVENT.equals(event.getType())) {
25             try {
26                 // Set JSP factory
27                 Class.forName("org.apache.jasper.compiler.JspRuntimeContext",
28                               true,
29                               this.getClass().getClassLoader());
30             } catch (Throwable t) {
31                 ExceptionUtils.handleThrowable(t);
32                 // Should not occur, obviously
33                 log.warn("Couldn't initialize Jasper", t);
34             }
35             // Another possibility is to do directly:
36             // JspFactory.setDefaultFactory(new JspFactoryImpl());
37         }
38 
39     }
40 
41 
42 }

重点关注来自接口的lifecycleEvent方法的实现,可以看到这个监听器只关心事件类型为BEFORE_INIT_EVENT的事件,如果发布了该事件,才会做后续处理(这里会产生一个org.apache.jasper.compiler.JspRuntimeContext对象)。

 

Lifecycle相关类UML关系图:

如果对设计模式比较熟悉的话会发现Tomcat的Lifecycle使用的是观察者模式:LifecycleListener代表的是抽象观察者,它定义一个lifecycleEvent方法,而实现该接口的监听器是作为具体的观察者。Lifecycle 接口代表的是抽象主题,它定义了管理观察者的方法和它要所做的其它方法。而各组件代表的是具体主题,它实现了抽象主题的所有方法。通常会由具体主题保存对具体观察者对象有用的内部状态;在这种内部状态改变时给其观察者发出一个通知。Tomcat对这种模式做了改进,增加了另外两个工具类:LifecycleSupport、LifecycleEvent,它们作为辅助类扩展了观察者的功能。LifecycleEvent中定义了事件类别,不同的事件在具体观察者中可区别处理,更加灵活。LifecycleSupport 类代理了所有具体主题对观察者的管理,将这个管理抽出来统一实现,以后如果修改只要修改 LifecycleSupport 类就可以了,不需要去修改所有具体主题,因为所有具体主题的对观察者的操作都被代理给 LifecycleSupport 类了。

 

事件的发布使用的是推模式,即每发布一个事件都会通知主题的所有具体观察者,由各观察者再来决定是否需要对该事件进行后续处理。

 

下面再来看看本文一开头所说的setStateInternal方法,以org.apache.catalina.core.StandardServer类为例,上面看到的startInternal方法中第4行:setState(LifecycleState.STARTING);

它调用了父类org.apache.catalina.util.LifecycleBase中的setState方法:

 1     /**
 2      * Provides a mechanism for sub-classes to update the component state.
 3      * Calling this method will automatically fire any associated
 4      * {@link Lifecycle} event. It will also check that any attempted state
 5      * transition is valid for a sub-class.
 6      * 
 7      * @param state The new state for this component
 8      */
 9     protected synchronized void setState(LifecycleState state)
10             throws LifecycleException {
11         setStateInternal(state, null, true);
12     }

在这个类里面调用本类的一个同步方法setStateInternal:

 1     private synchronized void setStateInternal(LifecycleState state,
 2             Object data, boolean check) throws LifecycleException {
 3         
 4         if (log.isDebugEnabled()) {
 5             log.debug(sm.getString("lifecycleBase.setState", this, state));
 6         }
 7         
 8         if (check) {
 9             // Must have been triggered by one of the abstract methods (assume
10             // code in this class is correct)
11             // null is never a valid state
12             if (state == null) {
13                 invalidTransition("null");
14                 // Unreachable code - here to stop eclipse complaining about
15                 // a possible NPE further down the method
16                 return;
17             }
18             
19             // Any method can transition to failed
20             // startInternal() permits STARTING_PREP to STARTING
21             // stopInternal() permits STOPPING_PREP to STOPPING and FAILED to
22             // STOPPING
23             if (!(state == LifecycleState.FAILED ||
24                     (this.state == LifecycleState.STARTING_PREP &&
25                             state == LifecycleState.STARTING) ||
26                     (this.state == LifecycleState.STOPPING_PREP &&
27                             state == LifecycleState.STOPPING) ||
28                     (this.state == LifecycleState.FAILED &&
29                             state == LifecycleState.STOPPING))) {
30                 // No other transition permitted
31                 invalidTransition(state.name());
32             }
33         }
34         
35         this.state = state;
36         String lifecycleEvent = state.getLifecycleEvent();
37         if (lifecycleEvent != null) {
38             fireLifecycleEvent(lifecycleEvent, data);
39         }
40     }

重点关注第35到39行,第35行将入参LifecycleState实例赋值给本类中的实例变量保存起来,第36行取出LifecycleState实例的LifecycleEvent事件,如果该事件非空,则调用fireLifecycleEvent方法发布该事件。

 

既然看到了LifecycleState类,就看下LifecycleState类的定义:

 1 public enum LifecycleState {
 2     NEW(false, null),
 3     INITIALIZING(false, Lifecycle.BEFORE_INIT_EVENT),
 4     INITIALIZED(false, Lifecycle.AFTER_INIT_EVENT),
 5     STARTING_PREP(false, Lifecycle.BEFORE_START_EVENT),
 6     STARTING(true, Lifecycle.START_EVENT),
 7     STARTED(true, Lifecycle.AFTER_START_EVENT),
 8     STOPPING_PREP(true, Lifecycle.BEFORE_STOP_EVENT),
 9     STOPPING(false, Lifecycle.STOP_EVENT),
10     STOPPED(false, Lifecycle.AFTER_STOP_EVENT),
11     DESTROYING(false, Lifecycle.BEFORE_DESTROY_EVENT),
12     DESTROYED(false, Lifecycle.AFTER_DESTROY_EVENT),
13     FAILED(false, null),
14     MUST_STOP(true, null),
15     MUST_DESTROY(false, null);
16 
17     private final boolean available;
18     private final String lifecycleEvent;
19 
20     private LifecycleState(boolean available, String lifecycleEvent) {
21         this.available = available;
22         this.lifecycleEvent = lifecycleEvent;
23     }
24 
25     /**
26      * May the public methods other than property getters/setters and lifecycle
27      * methods be called for a component in this state? It returns
28      * <code>true</code> for any component in any of the following states:
29      * <ul>
30      * <li>{@link #STARTING}</li>
31      * <li>{@link #STARTED}</li>
32      * <li>{@link #STOPPING_PREP}</li>
33      * <li>{@link #MUST_STOP}</li>
34      * </ul>
35      */
36     public boolean isAvailable() {
37         return available;
38     }
39 
40     /**
41      *
42      */
43     public String getLifecycleEvent() {
44         return lifecycleEvent;
45     }
46 }

这个类在之前的Tomcat4和Tomcat5中都没有看到,可能是Tomcat7里面新定义的吧,就是一个枚举,内嵌了两个实例变量,一个布尔值表示是否可用,一个字符串表示是事件类型,看已经定义的枚举值里面发现这个字符串要么不设值,要么就是Lifecycle类中定义好的字符串常量。这个类实际上就是对Lifecycle类中定义好的字符串常量做了另外一层封装。

 

再说回开头在各组件代码中经常会看到的setStateInternal方法的调用,实际上就是向该组件中已注册的监听器发布一个事件。

posted @ 2013-08-21 14:11  潜台词  阅读(229)  评论(0)    收藏  举报