Tomcat 9 源码分析(3)— 生命周期管理

Tomcat生命周期类接口设计

avator

  • Lifecycle:定义了容器生命周期,容器状态转换及容器状态迁移时间的监听器注册和移除等主要接口
  • LifecycleBase:作为Lifecycle接口的抽象实现类,运用抽象模板模式将所有容器的生命周期及状态转换衔接起来,此外还提供了生成LifecycleEvent事件的接口
  • LifecycleSupport:提供有关LifecycleEvent事件的监听器注册、移除,并且使用经典的监听器模式,实现事件生成后触发监听器的实现(目前已过时)
  • MBeanRegistration:Java JMX框架提供的注册MBean的接口,引入此几口是为了便于使用JMX提供的管理功能
  • LifecycleMBeanBase:Tomcat提供的对MBeanRegistration的抽象实现类,运用抽象模板模式将所有容器统一注册到JMX

此外,ContainerBase、StandardServer、StandardService、WebAppLoader、Connector、StandardContext、StandardEngine、StandardHost、StandardWrapper等容器都继承了LifecycleMBeanBase,因此这些容器都具有了同样的生命周期并可以通过JMX进行管理

JMX

Java管理程序扩展(java management extensions),是一个可以为Java应用程序或系统植入远程管理功能的框架

avator

  • Probe Level:负责资源的检测(获取信息),包含MBeans,通常也叫做Instrumentation Level。MX管理构建(MBean)分为四种形式,分别是标砖管理构建(Standard MBean)、动态管理构建(Dynamic MBean)、开放管理构建(Open MBean)和模型管理构建(Model MBean)
  • Agent Level:即MBeanServer,是JMX的核心,负责连接MBeans和应用程序
  • Remote Management Level:通过connectors和adaptors来远程操作MBeanServer,常用的控制台,例如JConsole,VisualVM等

Tomcat容器组成

StandardServer、StandardService、Connector、StandardContext这些容器,批次之间都有父子关系,每个容器都可能包含零个或多个子容器,这些子容器可能存在不同类型或相同类型的多个

avator

Tomcat容器状态

org.apache.catalina.LifecycleStat

public enum LifecycleState {
     //  NEW:容器刚刚创建时,即在LifecycleBase实例构造完成时的状态
     //  INITIALIZING:容器初始化过程中
     //  INITIALIZED:容器初始化完成时
     //  STARTING_PREP:容器启动前
     //  STARTING:容器启动过程中
     //  STARTED:容器启动完成
     //  STOPPING_PREP:容器停止前
     //  STOPPING:容器停止过程中
    //  STOPPED:容器停止完成
    //  DESTROYING:容器销毁过程中
    //  DESTROYED:容器销毁后
    //  FAILED:容器启动、停止过程中出现异常的状态
    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);

    private final boolean available;
    private final String lifecycleEvent;

    private LifecycleState(boolean available, String lifecycleEvent) {
        this.available = available;
        this.lifecycleEvent = lifecycleEvent;
    }
    public boolean isAvailable() {
        return available;
    }
    public String getLifecycleEvent() {
        return lifecycleEvent;
    }
}

容器状态转换

avator

事件与监听

每个容器都集成自LifecycleBase,当容器状态发生变化时,都会调用fireLifecycleEvent方法,生成LifecycleEvent,并且交由此容器的事件监听器处理。

注:旧版本中会使用LifecycleSupport结合实现,新版本直接由LifecycleBase实现

LifecycleBase的fireLifecycleEvent方法的实现:

protected void fireLifecycleEvent(String type, Object data) {
    LifecycleEvent event = new LifecycleEvent(this, type, data);
    for (LifecycleListener listener : lifecycleListeners) {
        listener.lifecycleEvent(event);
    }
}

fireLifecycleEvent()将事件通知给所有监听当前容器的生命周期监听器LifecycleListener,并调用LifecycleListener.lifecycleEvent()

每个容器都维护这一个监听器缓存lifecycleListeners的定义如下:

**
 * The list of registered LifecycleListeners for event notifications.
 */
private final List<LifecycleListener> lifecycleListeners = new CopyOnWriteArrayList<>();

每个容器在新建、初始化、启动、销毁,被添加到父容器的过程中都会调用LifecycleBase的addLifecycleListener方法,addLifecycleListener实现如下:

public void addLifecycleListener(LifecycleListener listener) {
    lifecycleListeners.add(listener);
}

各个容器都有lifecycleEvent的实现,其内完成的是容器产生Event时的处理

例如contextConfig:

org.apache.catalina.startup.ContextConfig

public void lifecycleEvent(LifecycleEvent event) {

    // Identify the context we are associated with
    try {
        context = (Context) event.getLifecycle();
    } catch (ClassCastException e) {
        log.error(sm.getString("contextConfig.cce", event.getLifecycle()), e);
        return;
    }

    // Process the event that has occurred
    if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
        configureStart();
    } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
        beforeStart();
    } else if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) {
        // Restore docBase for management tools
        if (originalDocBase != null) {
            context.setDocBase(originalDocBase);
        }
    } else if (event.getType().equals(Lifecycle.CONFIGURE_STOP_EVENT)) {
        configureStop();
    } else if (event.getType().equals(Lifecycle.AFTER_INIT_EVENT)) {
        init();
    } else if (event.getType().equals(Lifecycle.AFTER_DESTROY_EVENT)) {
        destroy();
    }

}

容器生命周期

每个容器都会有自身的生命周期,其中也涉及状态,以及伴随的事件生成。所有容器的状态转换都是由外到内,由上到下进行,即先执行父容器的状态转换及相关操作,然后再执行子容器的状态转换,这个过程是层层迭代执行的。

容器新建

所有容器在构造的过程中,都会首先对父类LifecycleBase进行构造。LifecycleBase中定义了所有容器的起始状态为LifecycleState.NEW

/**
 * The current state of the source component.
 */
private volatile LifecycleState state = LifecycleState.NEW;

容器初始化

每个容器的init方法都是自身初始化的入口。初始化过程:

avator

具体容器即LifecycleBase的具体实现类,Tomcat 9.0中LifecycleBase的类继承体系:

avator

根据初始化过程对Tomcat源码分析,其处理步骤如下:

  1. 调用放调用父类LifecycleBase的init方法,LifecycleBase的init方法主要完成一些所有容器公共抽象出来的动作

  2. LifecycleBase的init方法调由具体容器的initInternal方法实现,initInternal方法用于对容器本身真正的初始化

  3. 具体容器的initInternal方法调用父类LifecycleMBeanBbase的initInternal方法实现,此initIneral方法用于将容器托管到JMX,便于运维管理

  4. LifecycleMBeanBase的initInternal方法调用自身的register方法,将容器作为MBean方法注册到MBeanServer

  5. 容器如果有子容器,会调用子容器的init方法

  6. 容器初始化完毕,LifecycleBase会将容器的状态更改为初始化完毕,即LifecycleState.INITIALIZED

org.apache.catalina.util.LifecycleBase.init()

public final synchronized void init() throws LifecycleException {
    if (!state.equals(LifecycleState.NEW)) {
        invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
    }

    try {
        setStateInternal(LifecycleState.INITIALIZING, null, false);
        initInternal();
        setStateInternal(LifecycleState.INITIALIZED, null, false);
    } catch (Throwable t) {
        handleSubClassException(t, "lifecycleBase.initFail", toString());
    }
}

只有当前容器的状态处于LifecycleState.NEW的才可以被初始化,真正执行初始化的方法是initInernal,当初始化完毕,当前容器的状态会被更改为LifecycleState.INITIALIZED

(org.apache.catalina.core.StandardServer.initInternal()部分代码如下,StandardServer为LifecycleMBeanBase的某个具体实现,LifecycleMBeanBase继承LifecycleBase)

protected void initInternal() throws LifecycleException {
    //  调用父类的initInternal方法
    super.initInternal();

    reconfigureUtilityExecutor(getUtilityThreadsInternal(utilityThreads));
    register(utilityExecutor, "type=UtilityExecutor");

    onameStringCache = register(new StringCache(), "type=StringCache");

    MBeanFactory factory = new MBeanFactory();
    factory.setContainer(this);
    onameMBeanFactory = register(factory, "type=MBeanFactory");

    globalNamingResources.init();
    
    for (Service service : services) {
        service.init();
    }
}

通过分析StandardServer.initInternal(),发现其处理过程如下:

将当前容器注册到JMX

org.apache.catalina.util.LifecycleMBeanBase.initInternal()

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());
    }
}

调用分类LifecycleMBeanBase.initInternal(),为当前容器创造DynamicMBean,并注册到JMX中

org.apache.catalina.core.StandardServer实现的getObjectNameKeyProperties方法如下:

protected final String getObjectNameKeyProperties() {
    return "type=Server";
}

LifecycleBase的register方法会为当前容器创建对应的注册名称,以StandardServer为例,getDomain默认返回Catalina,因此StandardServer的JMX注册名称默认为Catalina:type=Server,真正的注册在registerComponent中实现

org.apache.catalina.util.LifecycleMBeanBase.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 (Exception e) {
        log.warn(sm.getString("lifecycleMBeanBase.registerFail", obj, name), e);
    }
    return on;
}

register的registerComponent()会为当前容器创建DynamicMBean,并且注册到MBeanServer

org.apache.catalina.util.LifecycleMBeanBase

public void registerComponent(Object bean, ObjectName oname, String type) throws Exception {
    if (log.isDebugEnabled()) {
        log.debug("Managed= " + oname);
    }
    if (bean == null) {
        log.error(sm.getString("registry.nullBean", oname));
        return;
    }
    try {
        if (type == null) {
            type = bean.getClass().getName();
        }

        ManagedBean managed = findManagedBean(null, 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(sm.getString("registry.registerError", oname), ex);
        throw ex;
    }
}

将StringCache、MBeanFactory、globalNamingResources注册到JMX

org.apache.catalina.core.StandardServer.initInternal()中,StringCache的注册名为Catalina:type=StringCache,MBeanFactory的注册名为Catalina:type=MBeanFactory,globalNamingResources的注册名为Catalina:type=NamingResources

初始化子容器

org.apache.catalina.core.StandardServer.initInternal()中主要对Service字容器进行初始化,默认是StandardService

注:个别容器并不完全遵循以上的初始化过程,比如ProtocolHandler作为Connector的子容器,其初始化并不是由Connector的initInternal方法调用的,而是与启动过程一道被connector的startInternal方法所调用

至此StandarSerever.initInternal()已分析完毕

容器启动

每个容器的start方法是自身启动的入口,启动过程如下:

avator

根据对源码的分析,其处理步骤如下:

  1. 调用方调用容器父类LifecycleBase的start方法,LifecycleBase的start方法主要完成一些容器公共抽象出来的动作

  2. LifecycleBase的start方法先将容器状态改为LifecycleState.STARTING_PREP,然后调用具体容器的startInternal方法实现,此startInternal方法用于对容器本身真正的初始化

  3. 具体容器的startInternal方法会将容器状态改为LifecycleState.STARTING,容器如果有子容器,会调用子容器的start方法启动子容器

  4. 容器启动完毕,LifecycleBase会将容器的状态更改为启动完毕,即LifecycleState.STARTED

org.apache.catalina.util.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);
    }

    try {
        setStateInternal(LifecycleState.STARTING_PREP, null, false);
        startInternal();
        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);
        }
    } catch (Throwable t) {
        // This is an 'uncontrolled' failure so put the component into the
        // FAILED state and throw an exception.
        handleSubClassException(t, "lifecycleBase.startFail", toString());
    }
}

真正启动容器之前需要做两种检查:

  • 如果当前容器已经处于启动状态(LifecycleState.STARTING_PREP、STARTING、STARTED)中,则会产生并且用日志记录LifecycleException异常并退出

  • 如果容器依然处于LifecycleState.NEW状态,则在启动前确保初始化完毕

容器启动完毕后,还需要做一种检查:

  • 如果容器启动异常导致容器进入LifecycleState.FAILED状态,则需要调 用stop方法停止容器

以org.apache.catalina.core.StandardServer.startInternal()为例:

protected void startInternal() throws LifecycleException {

    fireLifecycleEvent(CONFIGURE_START_EVENT, null);
    setState(LifecycleState.STARTING);

    globalNamingResources.start();

    // Start our defined Services
    synchronized (servicesLock) {
        for (Service service : services) {
            service.start();
        }
    }

    if (periodicEventDelay > 0) {
        monitorFuture = getUtilityExecutor().scheduleWithFixedDelay(
                () -> startPeriodicLifecycleEvent(), 0, 60, TimeUnit.SECONDS);
    }
}

启动步骤如下:

  1. 产生CONFIGURE_START_EVENT事件

  2. 将自身状态更改为LifecycleState.STARTING

  3. 调用子容器Service(StandardServer中默认为StandardService)的start方法启动子容器

  4. 设置生命周期事件周期

除了初始化、启动外,各个容器还有停止和销毁的生命周期,其原理与初始化、启动类似

Tomcat启动完毕后,打开Java visualVM,打开Tomcat进程监控,给visualVM安装MBeans插件后,选择MBeans标签页可以对Tomcat所有注册的到JMX中的对象进行管理,比如StandardService就向JMX暴露了start和stop等方法,这样管理员就可以动态管理Tomcat

总结

Tomcat通过将内部所有组件都抽象为容器,为容器提供统一的生命周期管理,各个子容器只需要关心各自的具体实现,这便于Tomcat以后扩展更多的容器,对于研究或者学习Tomcat的人来说,其设计清晰易懂

posted @ 2021-03-30 20:03  Kaiyko  阅读(139)  评论(0编辑  收藏  举报