在之前的 Tomcat 整体架构中可以看到 Tomcat 包含多个很多个组件 , 今天我们来看看, Tomcat 是如何管理这些组件的生命周期的。
我们知道,组件与组件之间,必须建立起相互的关系,才能做到同时启动与停止。 Tomcat 内部,使用一个观察者模式来组织这些组件之间的关系。
我们来看看, Tomcat 启动时,它会做哪些处理……
日志:
……
2010-6-19 15:41:18 org.apache.catalina.core.StandardService start
信息 : Starting service Catalina
2010-6-19 15:41:18 org.apache.catalina.core.StandardEngine start
信息 : Starting Servlet Engine: Apache Tomcat/6.0.18
…
2010-6-19 15:41:19 org.apache.coyote.http11.Http11Protocol start
信息 : Starting Coyote HTTP/1.1 on http-8080
2010-6-19 15:41:19 org.apache.jk.common.ChannelSocket init
信息 : JK: ajp13 listening on /0.0.0.0:8009
2010-6-19 15:41:19 org.apache.jk.server.JkMain start
信息 : Jk running ID=0 time=0/182 config=null
2010-6-19 15:41:19 org.apache.catalina.startup.Catalina start
信息 : Server startup in 1706 ms
我们看到,它的启动顺序:
StandardService --> StandardEngine-->Http11Protocol-->JkMain-->Catalina
OK, 我们来看看在 Tomcat 内部的,他是如何做的
首先, Tomcat内部的生命周期的相关定义都在接口 Lifecycle 中,
package org.apache.catalina;
public interface Lifecycle {
public static final String INIT_EVENT = "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 DESTROY_EVENT = "destroy";
public static final String PERIODIC_EVENT = "periodic";
public void addLifecycleListener(LifecycleListener listener);
public LifecycleListener[] findLifecycleListeners();
public void removeLifecycleListener(LifecycleListener listener);
public void start() throws LifecycleException;
public void stop() throws LifecycleException;
}
另外生命周期的相关事件,定义在 LifecycleEvent 类中
package org.apache.catalina;
import java.util.EventObject;
public final class LifecycleEvent
extends EventObject {
// ----------------------------------------------------------- Constructors
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);
}
}
关于事件的监听,在接口LifecycleListener 中有定义
package org.apache.catalina;
public interface LifecycleListener {
public void lifecycleEvent(LifecycleEvent event);
}
另外,这里还需要介绍一个特别的类: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];
private final Object listenersLock = new Object(); // Lock object for changes to listeners
public void addLifecycleListener(LifecycleListener listener) {
synchronized (listenersLock) {
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[] = listeners;
for (int i = 0; i < interested.length; i++)
interested[i].lifecycleEvent(event);
}
public void removeLifecycleListener(LifecycleListener listener) {
synchronized (listenersLock) {
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;
}
}
}
下面,我们来看看 StandardService 类的启动方法, 看它是如何启动的
在service真正启动时,他首先会触发一些启动前的事件,
然后启动它自己
接着,它会启动它关联的容器对象,
然后,将所有它的子组件—既连接器 全部都启动 ,下面是详细的代码/
public class StandardService
implements Lifecycle, Service, MBeanRegistration
{
.............
/**
* The lifecycle event support for this component.
*/
private LifecycleSupport lifecycle = new LifecycleSupport(this);
.............
/**
* The set of Connectors associated with this Service.
关联到这个Service的连接器对象.
*/
protected Connector connectors[] = new Connector[0];
public void start() throws LifecycleException {
// Validate and update our current component state
if (log.isInfoEnabled() && started) {
log.info(sm.getString("standardService.start.started"));
}
if( ! initialized )
init();
// 触发启动之前的事件
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
if(log.isInfoEnabled())
log.info(sm.getString("standardService.start.name", this.name));
lifecycle.fireLifecycleEvent(START_EVENT, null); <<<<(1)
started = true;
// Start our defined Container first 首先启动关联的容器
if (container != null) {
synchronized (container) {
if (container instanceof Lifecycle) {
((Lifecycle) container).start();
}
}
}
synchronized (executors) {
for ( int i=0; i<executors.size(); i++ ) {
executors.get(i).start();
}
}
// Start our defined Connectors second 再启动关联的连接器
synchronized (connectors) {
for (int i = 0; i < connectors.length; i++) {
if (connectors[i] instanceof Lifecycle)
((Lifecycle) connectors[i]).start();
}
}
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}
代码(1)处,显示出,在Service正式启动之前,它还会出发启动前的事件,我们来看看,这个方法具体做些什么. 调用LifecycleSupport 类的 fireLifecycleEvent(START_EVENT, null);方法
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);
}
而在内部,Service启动时,这里真正调用的是类 ServerLifecycleListener的方法:
package org.apache.catalina.mbeans;
public class ServerLifecycleListener
implements ContainerListener, LifecycleListener, PropertyChangeListener {
public void lifecycleEvent(LifecycleEvent event) {
Lifecycle lifecycle = event.getLifecycle();
if (Lifecycle.START_EVENT.equals(event.getType())) {
if (lifecycle instanceof Server) {
createMBeans();
}
// We are embedded.
if( lifecycle instanceof Service ) {
try {
//Service启动时,触发的事件
MBeanFactory factory = new MBeanFactory();
createMBeans(factory);
createMBeans((Service)lifecycle);
} catch( Exception ex ) {
log.error("Create mbean factory");
}
}
/*
// Ignore events from StandardContext objects to avoid
// reregistering the context
if (lifecycle instanceof StandardContext)
return;
createMBeans();
*/
} else if (Lifecycle.AFTER_STOP_EVENT.equals(event.getType())) {
try {
if (lifecycle instanceof Server) {
destroyMBeans((Server)lifecycle);
}
if (lifecycle instanceof Service) {
destroyMBeans((Service)lifecycle);
}
} catch (MBeanException t) {
Exception e = t.getTargetException();
if (e == null) {
e = t;
}
log.error("destroyMBeans: MBeanException", e);
} catch (Throwable t) {
log.error("destroyMBeans: Throwable", t);
}
// FIXME: RMI adaptor should be stopped; however, this is
// undocumented in MX4J, and reports exist in the MX4J bug DB that
// this doesn't work
}
if ((Context.RELOAD_EVENT.equals(event.getType()))
|| (Lifecycle.START_EVENT.equals(event.getType()))) {
// Give context a new handle to the MBean server if the
// context has been reloaded since reloading causes the
// context to lose its previous handle to the server
if (lifecycle instanceof StandardContext) {
// If the context is privileged, give a reference to it
// in a servlet context attribute
StandardContext context = (StandardContext)lifecycle;
if (context.getPrivileged()) {
context.getServletContext().setAttribute
(Globals.MBEAN_REGISTRY_ATTR,
MBeanUtils.createRegistry());
context.getServletContext().setAttribute
(Globals.MBEAN_SERVER_ATTR,
MBeanUtils.createServer());
}
}
}
}
}
这里简单介绍一下,Tomcat内部的启动流程, 通过观察者模式与监听器模式来作处理, 组件启动方面,在启动上级组件的同时,先启动下一级组件, (当然,在父组件内部,需要包含它所有子组件引用的一个集合).