TOMCAT源码分析——生命周期管理(一)

简介: 前言   从server.xml文件解析出来的各个对象都是容器,比如:Server、Service、Connector等。这些容器都具有新建、初始化完成、启动、停止、失败、销毁等状态。tomcat的实现提供了对这些容器的生命周期管理,本文将通过对Tomcat7.0的源码阅读,深入剖析这一过程。

前言

  从server.xml文件解析出来的各个对象都是容器,比如:Server、Service、Connector等。这些容器都具有新建、初始化完成、启动、停止、失败、销毁等状态。tomcat的实现提供了对这些容器的生命周期管理,本文将通过对Tomcat7.0的源码阅读,深入剖析这一过程。

TOMCAT生命周期类接口设计

  我们先阅读图1,从中了解Tomcat涉及生命周期管理的主要类。
Tomcat_
图1  Tomcat生命周期类接口设计
这里对图1中涉及的主要类作个简单介绍:

  • 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,简称JMX),是一个可以为Java应用程序或系统植入远程管理功能的框架。为便于讲解,我从网络上找了一张JMX的架构,如图2所示。
    JMX_
    图2  JMX架构
    这里对图2中三个分层进行介绍:

  • 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这些容器,彼此之间都有父子关系,每个容器都可能包含零个或者多个子容器,这些子容器可能存在不同类型或者相同类型的多个,如图3所示。
    Tomcat_
    图3  Tomcat容器组成

    TOMCAT容器状态

      目前,Tomcat的容器具有以下状态:

  • NEW:容器刚刚创建时,即在LifecycleBase实例构造完成时的状态。

  • INITIALIZED:容器初始化完成时的状态。

  • STARTING_PREP:容器启动前的状态。

  • STARTING:容器启动过程中的状态。

  • STARTED:容器启动完成的状态。

  • STOPPING_PREP:容器停止前的状态。

  • STOPPING:容器停止过程中的状态。

  • STOPPED:容器停止完成的状态。

  • DESTROYED:容器销毁后的状态。

  • FAILED:容器启动、停止过程中出现异常的状态。

  • MUST_STOP:此状态未使用。

  • MUST_DESTROY:此状态未使用。
    这些状态都定义在枚举类LifecycleState中。

    事件与监听

      每个容器由于继承自LifecycleBase,当容器状态发生变化时,都会调用fireLifecycleEvent方法,生成LifecycleEvent,并且交由此容器的事件监听器处理。LifecycleBase的fireLifecycleEvent方法的实现见代码清单1。
    代码清单1

    /**
     * Allow sub classes to fire {@link Lifecycle} events.
     * 
     * @param type  Event type
     * @param data  Data associated with event.
     */
    protected void fireLifecycleEvent(String type, Object data) {
        lifecycle.fireLifecycleEvent(type, data);
    }
    

    lifecycle的定义如下:

    /**
     * Used to handle firing lifecycle events.
     * TODO: Consider merging LifecycleSupport into this class.
     */
    private LifecycleSupport lifecycle = new LifecycleSupport(this);
    

    LifecycleSupport的fireLifecycleEvent方法的实现,见代码清单2。
    代码清单2

    /**
     * Notify all lifecycle event listeners that a particular event has
     * occurred for this Container.  The default implementation performs
     * this notification synchronously using the calling thread.
     *
     * @param type Event type
     * @param data Event data
     */
    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);
    
    }
    

    代码清单2将事件通知给所有监听当前容器的生命周期监听器LifecycleListener,并调用LifecycleListener的lifecycleEvent方法。每个容器都维护这一个监听器缓存,其实现如下:

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

    那么listeners中的监听器是何时添加进来的呢?每个容器在新建、初始化、启动,销毁,被添加到父容器的过程中都会调用父类LifecycleBase的addLifecycleListener方法,addLifecycleListener的实现见代码清单3。
    代码清单3

    @Override
    public void addLifecycleListener(LifecycleListener listener) {
        lifecycle.addLifecycleListener(listener);
    }
    

    从代码清单3看到,LifecycleBase的addLifecycleListener方法实际是对LifecycleSupport的addLifecycleListener方法的简单代理,LifecycleSupport的addLifecycleListener方法的实现,见代码清单4。
    代码清单4

    /**
     * Add a lifecycle event listener to this component.
     *
     * @param listener The listener to add
     */
    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;
      }
    
    }
    

    在代码清单2中,我们讲过容器会最终调用每个对此容器感兴趣的LifecycleListener的lifecycleEvent方法,那么LifecycleListener的lifecycleEvent方法会做些什么呢?为了简单起见,我们以监听器AprLifecycleListener为例,AprLifecycleListener的lifecycleEvent方法的实现,见代码清单5。
    代码清单5

    /**
     * Primary entry point for startup and shutdown events.
     *
     * @param event The event that has occurred
     */
    public void lifecycleEvent(LifecycleEvent event) {
    
        if (Lifecycle.INIT_EVENT.equals(event.getType())) {
            synchronized (lock) {
                init();
                if (aprAvailable) {
                    try {
                        initializeSSL();
                    } catch (Throwable t) {
                        log.info(sm.getString("aprListener.sslInit"));
                    }
                }
            }
        } else if (Lifecycle.AFTER_STOP_EVENT.equals(event.getType())) {
            synchronized (lock) {
                if (!aprAvailable) {
                    return;
                }
                try {
                    terminateAPR();
                } catch (Throwable t) {
                    log.info(sm.getString("aprListener.aprDestroy"));
                }
            }
        }
    
    }
    

    我会在《TOMCAT源码分析——生命周期管理(二)》一文中继续讲解容器生命周期的其它内容。

相关文章
|
4月前
|
XML Java 应用服务中间件
SpringBoot配置外部Tomcat项目启动流程源码分析(长文)
SpringBoot配置外部Tomcat项目启动流程源码分析(长文)
48 0
|
9月前
|
存储 缓存 前端开发
07.Tomcat源码分析——类加载体系
由于在生产环境中,Tomcat一般部署在Linux系统下,所以本文将以 startup.sh shell脚本为准,对Tomcat的启动进行分析。
31 0
07.Tomcat源码分析——类加载体系
|
10月前
|
前端开发 Java 应用服务中间件
TOMCAT 源码分析 -- 一次请求
TOMCAT 源码分析 -- 一次请求
66 0
|
10月前
|
Java 应用服务中间件
TOMCAT 源码分析 -- 构建环境
TOMCAT 源码分析 -- 构建环境
77 0
|
10月前
|
监控 前端开发 Java
TOMCAT 源码分析 -- 启动(下)
TOMCAT 源码分析 -- 启动
71 0
|
10月前
|
XML 前端开发 Java
TOMCAT 源码分析 -- 启动(上)
TOMCAT 源码分析 -- 启动
104 0
|
10月前
|
Java 应用服务中间件 容器
Tomcat源码分析之中文乱码(一)
Tomcat源码分析之中文乱码(一)
137 0
|
10月前
|
算法 安全 应用服务中间件
Tomcat源码分析之 doGet方法(四)
Tomcat源码分析之 doGet方法(四)
33 0
|
10月前
|
设计模式 应用服务中间件 容器
Tomcat源码分析之 doGet方法(三)
Tomcat源码分析之 doGet方法(三)
42 0
|
10月前
|
应用服务中间件 索引
Tomcat源码分析之 doGet方法(二)
Tomcat源码分析之 doGet方法(二)
55 0