想必你们都知道,从server.xml文件解析出来的各个对象都是容器,好比:Server、Service、Connector等。这些容器都具备新建、初始化完成、启动、中止、失败、销毁等状态。Tomcat的实现机制是经过实现org.apache.catalina.Lifecycle接口来管理。apache
定义了容器生命周期、容器状态转换及容器状态迁移事件的监听器注册和移除等主要接口。代码清单:服务器
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 void destroy() throws LifecycleException; public LifecycleState getState(); public String getStateName(); public interface SingleUse { } }
其中,最重要的方法时start和stop方法。父组件经过这两个方法来启动/关闭该组件。addLifecycleListener,findLifecycleListeners,removeLifecycleListener三个方法用于向组件注册/查找/删除监听器。当事件发生时,会触发监听器。接口中还定义了相关事件。网络
下面从一幅图来了解Tomcat涉及生命周期管理的主要类:app
从上图能够看出ContainerBase、StandardServer、StandardService、WebappLoader、Connector、StandardContext、StandardEngine、StandardHost、StandardWrapper等容器都继承了LifecycleMBeanBase,所以这些容器都具备了一样的生命周期并能够经过JMX进行管理。框架
JMX(Java Management Extensions,即Java管理扩展)是一个为应用程序、设备、系统等植入管理功能的框架。JMX能够跨越一系列异构操做系统平台、系统体系结构和网络传输协议,灵活的开发无缝集成的系统、网络和服务管理应用。运维
JMX体系结构分为如下四个层次:dom
设备层ui
设备层(Instrumentation Level):主要定义了信息模型。在JMX中,各类管理对象以管理构件的形式存在,须要管理时,向MBean服务器进行注册。该层还定义了通知机制以及一些辅助元数据类。this
代理层网络传输协议
代理层(Agent Level):主要定义了各类服务以及通讯模型。该层的核心是一个MBean服务器,全部的管理构件都须要向它注册,才能被管理。注册在MBean服务器上管理构件并不直接和远程应用程序进行通讯,它们经过协议适配器和链接器进行通讯。而协议适配器和链接器也以管理构件的形式向MBean服务器注册才能提供相应的服务。
分布服务层
分布服务层(Distributed Service Level):主要定义了能对代理层进行操做的管理接口和构件,这样管理者就能够操做代理。然而,当前的JMX规范并无给出这一层的具体规范。
附加管理协议API
定义的API主要用来支持当前已经存在的网络管理协议,如SNMP、TMN、CIM/WBEM等。
每一个容器因为继承自LifecycleBase,当容器状态发生变化时,都会调用fireLifecycleEvent方法,生成LifecycleEvent,而且交由此容器的事件监听器处理。
LifecycleBase的fireLifecycleEvent方法的实现:
protected void fireLifecycleEvent(String type, Object data) { lifecycle.fireLifecycleEvent(type, data); } //lifecycle定义 private LifecycleSupport lifecycle = new LifecycleSupport(this); //LifecycleSupport的fireLifecycleEvent方法的实现 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); }
而后将事件通知给全部监听当前容器的生命周期监听器LifecycleListener,并调用LifecycleListener的lifecycleEvent方法。
那么监听器LifecycleListener是什么时候注册进来的?其实每一个容器在新建、初始化、启动,销毁,被添加到父容器的过程当中都会调用父类LifecycleBase的addLifecycleListener方法:
public void addLifecycleListener(LifecycleListener listener) { lifecycle.addLifecycleListener(listener); }
LifecycleBase的addLifecycleListener方法实际是对LifecycleSupport的addLifecycleListener方法的简单代理,LifecycleSupport的addLifecycleListener方法的实现:
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; } }
容器会最终调用每一个对此容器感兴趣的LifecycleListener的lifecycleEvent方法,那么LifecycleListener的lifecycleEvent方法会作些什么呢?为了简单起见,咱们以监听器JasperListener为例,JasperListener的lifecycleEvent方法的实现:
public void lifecycleEvent(LifecycleEvent event) { if (Lifecycle.BEFORE_INIT_EVENT.equals(event.getType())) { try { // Set JSP factory Class.forName("org.apache.jasper.compiler.JspRuntimeContext", true, this.getClass().getClassLoader()); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); // Should not occur, obviously log.warn("Couldn't initialize Jasper", t); } // Another possibility is to do directly: // JspFactory.setDefaultFactory(new JspFactoryImpl()); } }
StandardServer、StandardService、Connector、StandardContext这些容器,彼此之间都有父子关系,每一个容器均可能包含零个或者多个子容器,这些子容器可能存在不一样类型或者相同类型的多个。在一个容器建立成功后,会有如下状态:
NEW:容器刚刚建立时,即在LifecycleBase实例构造完成时的状态。
INITIALIZED:容器初始化完成时的状态。
STARTING_PREP:容器启动前的状态。
STARTING:容器启动过程当中的状态。
STARTED:容器启动完成的状态。
STOPPING_PREP:容器中止前的状态。
STOPPING:容器中止过程当中的状态。
STOPPED:容器中止完成的状态。
DESTROYED:容器销毁后的状态。
FAILED:容器启动、中止过程当中出现异常的状态。
MUST_STOP:此状态未使用。
MUST_DESTROY:此状态未使用。
这些状态都定义在枚举类LifecycleState中。代码详单:
public enum LifecycleState { NEW(false, null), INITIALIZING(false, Lifecycle.BEFORE_INIT_EVENT), INITIALIZED(false, Lifecycle.AFTER_INIT_EVENT), STARTING_PREP(false, Lifecycle.BEFORE_START_EVENT), STARTING(true, Lifecycle.START_EVENT), STARTED(true, Lifecycle.AFTER_START_EVENT), STOPPING_PREP(true, Lifecycle.BEFORE_STOP_EVENT), STOPPING(false, Lifecycle.STOP_EVENT), STOPPED(false, Lifecycle.AFTER_STOP_EVENT), DESTROYING(false, Lifecycle.BEFORE_DESTROY_EVENT), DESTROYED(false, Lifecycle.AFTER_DESTROY_EVENT), FAILED(false, null), /** * @deprecated Unused. Will be removed in Tomcat 9.0.x. The state transition * checking in {[@link](http://my.oschina.net/u/393) org.apache.catalina.util.LifecycleBase} * makes it impossible to use this state. The intended behaviour * can be obtained by setting the state to * {[@link](http://my.oschina.net/u/393) LifecycleState#FAILED} in * <code>LifecycleBase.startInternal()</code> */ @Deprecated MUST_STOP(true, null), /** * @deprecated Unused. Will be removed in Tomcat 9.0.x. The state transition * checking in {@link org.apache.catalina.util.LifecycleBase} * makes it impossible to use this state. The intended behaviour * can be obtained by implementing {@link Lifecycle.SingleUse}. */ @Deprecated MUST_DESTROY(false, null); private final boolean available; private final String lifecycleEvent; private LifecycleState(boolean available, String lifecycleEvent) { this.available = available; this.lifecycleEvent = lifecycleEvent; } /** * May the public methods other than property getters/setters and lifecycle * methods be called for a component in this state? It returns * <code>true</code> for any component in any of the following states: * <ul> * <li>{@link #STARTING}</li> * <li>{@link #STARTED}</li> * <li>{@link #STOPPING_PREP}</li> * <li>{@link #MUST_STOP}</li> * </ul> */ public boolean isAvailable() { return available; } /** * */ public String getLifecycleEvent() { return lifecycleEvent; } }
每一个容器都会有自身的生命周期,其中也涉及状态的迁移,以及伴随的事件生成。全部容器的状态转换(如新建、初始化、启动、中止等)都是由外到内,由上到下进行,即先执行父容器的状态转换及相关操做,而后再执行子容器的转态转换,这个过程是层层迭代执行的。
全部容器在构造的过程当中,都会首先对父类LifecycleBase进行构造。LifecycleBase中定义了全部容器的起始状态为LifecycleState.NEW。
private volatile LifecycleState state = LifecycleState.NEW;
每一个容器的init方法是自身初始化的入口,其初始化过程如图所示:
调用方调用容器父类LifecycleBase的init方法,LifecycleBase的init方法主要完成一些全部容器公共抽象出来的动做;
LifecycleBase的init方法调用具体容器的initInternal方法实现,此initInternal方法用于对容器自己真正的初始化;
具体容器的initInternal方法调用父类LifecycleMBeanBase的initInternal方法实现,此initInternal方法用于将容器托管到JMX,便于运维管理;
LifecycleMBeanBase的initInternal方法调用自身的register方法,将容器做为MBean注册到MBeanServer;
容器若是有子容器,会调用子容器的init方法;
容器初始化完毕,LifecycleBase会将容器的状态更改成初始化完毕,即LifecycleState.INITIALIZED。
init方法的实现
public final synchronized void init() throws LifecycleException { if (!state.equals(LifecycleState.NEW)) { invalidTransition(Lifecycle.BEFORE_INIT_EVENT); } setStateInternal(LifecycleState.INITIALIZING, null, false); try { initInternal();//调用具体容器的initInternal方法实现 } catch (Throwable t) { ExceptionUtils.handleThrowable(t); setStateInternal(LifecycleState.FAILED, null, false); throw new LifecycleException( sm.getString("lifecycleBase.initFail",toString()), t); } setStateInternal(LifecycleState.INITIALIZED, null, false); }
只有当前容器的状态处于LifecycleState.NEW的才能够被初始化,真正执行初始化的方法是initInternal,当初始化完毕,当前容器的状态会被更改成LifecycleState.INITIALIZED。以StandardService这个容器为例举例分析,StandardService容器的initInternal方法实现:
protected void initInternal() throws LifecycleException { super.initInternal(); if (container != null) { container.init(); } // Initialize any Executors for (Executor executor : findExecutors()) { if (executor instanceof LifecycleMBeanBase) { ((LifecycleMBeanBase) executor).setDomain(getDomain()); } executor.init(); } // Initialize our defined Connectors synchronized (connectorsLock) { for (Connector connector : connectors) { try { connector.init(); } catch (Exception e) { String message = sm.getString( "standardService.connector.initFailed", connector); log.error(message, e); if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) throw new LifecycleException(message); } } } }
其处理过程:
a、调用父类LifecycleBase的initInternal方法,为当前容器建立DynamicMBean,并注册到JMX中。
protected void initInternal() throws LifecycleException { // If oname is not null then registration has already happened via // preRegister(). if (oname == null) { mserver = Registry.getRegistry(null, null).getMBeanServer(); oname = register(this, getObjectNameKeyProperties()); } } //getObjectNameKeyProperties()方法 public final String getObjectNameKeyProperties() { return "type=Service"; }
LifecycleBase的register方法会为当前容器建立对应的注册名称,以StandardService为例,getDomain默认返回Catalina,所以StandardService的JMX注册名称默认为Catalina:type=Service,真正的注册在registerComponent方法中实现。
//register方法 protected final ObjectName register(Object obj, String objectNameKeyProperties) { // Construct an object name with the right domain StringBuilder name = new StringBuilder(getDomain()); name.append(':'); name.append(objectNameKeyProperties); ObjectName on = null; try { on = new ObjectName(name.toString()); Registry.getRegistry(null, null).registerComponent(obj, on, null); } catch (MalformedObjectNameException e) { log.warn(sm.getString("lifecycleMBeanBase.registerFail", obj, name), e); } catch (Exception e) { log.warn(sm.getString("lifecycleMBeanBase.registerFail", obj, name), e); } return on; } //registerComponent方法 public void registerComponent(Object bean, ObjectName oname, String type) throws Exception { if( log.isDebugEnabled() ) { log.debug( "Managed= "+ oname); } if( bean ==null ) { log.error("Null component " + oname ); return; } try { if( type==null ) { type=bean.getClass().getName(); } ManagedBean managed = findManagedBean(bean.getClass(), type); // The real mbean is created and registered DynamicMBean mbean = managed.createMBean(bean); if( getMBeanServer().isRegistered( oname )) { if( log.isDebugEnabled()) { log.debug("Unregistering existing component " + oname ); } getMBeanServer().unregisterMBean( oname ); } getMBeanServer().registerMBean( mbean, oname); } catch( Exception ex) { log.error("Error registering " + oname, ex ); throw ex; } }
Registry的registerComponent方法会为当前容器(如StandardService)建立DynamicMBean,而且注册到MBeanServer中。
b、将StringCache、MBeanFactory、globalNamingResources注册到JMX
其中StringCache的注册名为Catalina:type=StringCache,MBeanFactory的注册名为Catalina:type=MBeanFactory,globalNamingResources的注册名为Catalina:type=NamingResources(如StandardService则为:Catalina:type=Service)
c、初始化子容器
主要对Service子容器进行初始化,默认是StandardService。
注意:个别容器并不彻底遵循以上的初始化过程,好比ProtocolHandler做为Connector的子容器,其初始化过程并非由Connector的initInternal方法调用的,而是与启动过程一道被Connector的startInternal方法所调用。
每一个容器的start方法是自身启动的入口
调用方调用容器父类LifecycleBase的start方法,LifecycleBase的start方法主要完成一些全部容器公共抽象出来的动做;
LifecycleBase的start方法先将容器状态改成LifecycleState.STARTING_PREP,而后调用具体容器的startInternal方法实现,此startInternal方法用于对容器自己真正的初始化;
具体容器的startInternal方法会将容器状态改成LifecycleState.STARTING,容器若是有子容器,会调用子容器的start方法启动子容器;
容器启动完毕,LifecycleBase会将容器的状态更改成启动完毕,即LifecycleState.STARTED。
//LifecycleBase的start方法 public final synchronized void start() throws LifecycleException { if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) || LifecycleState.STARTED.equals(state)) { if (log.isDebugEnabled()) { Exception e = new LifecycleException(); log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e); } else if (log.isInfoEnabled()) { log.info(sm.getString("lifecycleBase.alreadyStarted", toString())); } return; } if (state.equals(LifecycleState.NEW)) { init(); } else if (state.equals(LifecycleState.FAILED)) { stop(); } else if (!state.equals(LifecycleState.INITIALIZED) && !state.equals(LifecycleState.STOPPED)) { invalidTransition(Lifecycle.BEFORE_START_EVENT); } setStateInternal(LifecycleState.STARTING_PREP, null, false); try { startInternal(); } catch (Throwable t) { // This is an 'uncontrolled' failure so put the component into the // FAILED state and throw an exception. ExceptionUtils.handleThrowable(t); setStateInternal(LifecycleState.FAILED, null, false); throw new LifecycleException(sm.getString("lifecycleBase.startFail", toString()), t); } if (state.equals(LifecycleState.FAILED)) { // This is a 'controlled' failure. The component put itself into the // FAILED state so call stop() to complete the clean-up. stop(); } else if (!state.equals(LifecycleState.STARTING)) { // Shouldn't be necessary but acts as a check that sub-classes are // doing what they are supposed to. invalidTransition(Lifecycle.AFTER_START_EVENT); } else { setStateInternal(LifecycleState.STARTED, null, false); } }
在真正启动容器以前须要作2种检查:
若是当前容器已经处于启动过程(即容器状态为LifecycleState.STARTING_PREP、LifecycleState.STARTING、LifecycleState.STARTED)中,则会产生而且用日志记录LifecycleException异常并退出。 若是容器依然处于LifecycleState.NEW状态,则在启动以前,首先确保初始化完毕。
启动容器完毕后,须要作1种检查: 即若是容器启动异常致使容器进入LifecycleState.FAILED或者LifecycleState.MUST_STOP状态,则须要调用stop方法中止容器。
以StandardService为例,其startInternal的实现:
protected void startInternal() throws LifecycleException { if(log.isInfoEnabled()) log.info(sm.getString("standardService.start.name", this.name)); setState(LifecycleState.STARTING);//将自身状态更改成LifecycleState.STARTING; // Start our defined Container first if (container != null) { synchronized (container) { container.start();//调用子容器Service的start方法启动子容器。 } } synchronized (executors) { for (Executor executor: executors) { executor.start(); } } // Start our defined Connectors second synchronized (connectorsLock) { for (Connector connector: connectors) { try { // If it has already failed, don't try and start it if (connector.getState() != LifecycleState.FAILED) { connector.start(); } } catch (Exception e) { log.error(sm.getString( "standardService.connector.startFailed", connector), e); } } } }
除了初始化、启动外,各个容器还有中止和销毁的生命周期,其原理与初始化、启动相似。
Tomcat经过将内部全部组件都抽象为容器,为容器提供统一的生命周期管理,各个子容器只须要关心各自的具体实现,这便于Tomcat之后扩展更多的容器。