本文转自:http://www.iteye.com/topic/694644
在之前的 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内部的启动流程, 通过观察者模式与监听器模式来作处理, 组件启动方面,在启动上级组件的同时,先启动下一级组件, (当然,在父组件内部,需要包含它所有子组件引用的一个集合).