tomcat + spring mvc原理(二):tomcat容器动态加载

  • 容器通用生命周期标准
  • 容器通用生命周期的实现
    • 生命周期状态监听器的管理实现
    • 生命周期方法实现
  • 宏观来看各种容器生命周期的实际流程

tomcat + spring mvc 原理(一):tomcat原理综述比较详细的叙述了tomcat容器的静态结构和容器的配置,从tomcat动态运行来讲,我也在 原理(一)中简单论述了:

显然,这种运作模式要求:tomcat需要有监视指定目录,一旦有新的war包加入,就完成解包并动态加载编译后的class的能力;tomcat需要有网络端口开闭和监视的机制,维护线程池来处理随时可能到来的请求;tomcat还需要将到来的请求顺利地传递给spring mvc服务,然后再将服务返回的数据发送出去。

其实,对tomcat的理解,不只是应该了解静态容器结构,对于动态运行方面,应该包括:

  1. 容器的初始加载和启动
  2. war包动态监视和加载
  3. 网络请求的监控和处理

这样基本就涵盖了tomcat所有的基本运作原理。本文主要涉及第一部分:容器的初始加载与启动。

容器通用生命周期标准

tomcat的容器,包括Server、Service、Connector、Engine、Host、Context、Wrapper都继承自同一个管理生命周期的接口:Lifecycle。
    首先,这个接口类定义了这些容器的初始化、启动、停止和销毁的标准生命周期方法。

public interface Lifecycle {......//容器初始化public void init() throws LifecycleException;//容器启动public void start() throws LifecycleException;//容器停止public void stop() throws LifecycleException;//容器销毁public void destroy() throws LifecycleException;......
}

其次,这个接口类定义了这些容器所处生命周期的状态事件名和状态事件监听器的管理。

public interface Lifecycle {....../***13种生命周期状态事件的名字。通过名字还是比较比较好理解的**/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 LifecycleState getState();//获取状态名public String getStateName();/***状态事件监听器。LifecycleListener中包含一个处理事件的方*法LifecycleEvent()**///添加状态事件监听器public void addLifecycleListener(LifecycleListener listener);//获取所有状态事件监听器public LifecycleListener[] findLifecycleListeners();//移除状态事件监听器public void removeLifecycleListener(LifecycleListener listener);......
}

容器通用生命周期的实现

Lifecycle接口类的通用实现是在LifecycleBase类中。
    容器都继承自LifeCycleBase类,LifecycleBase类为容器提供了基本生命周期方法的一般实现和生命周期状态监听器的管理实现。

  • 生命周期状态监听器的管理实现

这一部分主要是监听器管理的实现,但真正发挥作用是在生命周期方法的实现中。
    LifecycleBase中使用一个自己定义的List–CopyOnWriteArrayList来存储LifecycleListener,本质上还是一个List,具体实现过于细节,这里不做研究。同时LifecycleBase基于监听器的List,对添加监听器、移除监听器、获取所有监听器的方法实现了逻辑。

private final List<LifecycleListener> lifecycleListeners = new CopyOnWriteArrayList<>();
//添加状态事件监听器的方法实现
@Override
public void addLifecycleListener(LifecycleListener listener) {lifecycleListeners.add(listener);
}
//获取所有状态事件监听器的方法实现
@Override
public LifecycleListener[] findLifecycleListeners() {return lifecycleListeners.toArray(new LifecycleListener[0]);
}
//移除状态事件监听器的方法实现
@Override
public void removeLifecycleListener(LifecycleListener listener) {lifecycleListeners.remove(listener);
}

需要特别注意的是,LifecycleBase实现了生命周期状态事件监听器处理事件的方法,其实就是遍历了监听器List,使用监听器的lifecleEvent方法处理了事件。这一方法在后面实现的init(),start()等生命周期的方法中都有间接调用,相当于只要更改了容器所处生命周期的状态,就需要对发布这一事件,调用该容器的关注该事件的监听器处理事件。

protected void fireLifecycleEvent(String type, Object data) {LifecycleEvent event = new LifecycleEvent(this, type, data);for (LifecycleListener listener : lifecycleListeners) {listener.lifecycleEvent(event);}
}
  • 生命周期方法实现

LifecycleBase实现了Lifecycle的标准生命周期方法init()、start()、stop()、destroy()的逻辑。下面主要以init()和start()为例介绍实现的基本特点。

//init()生命周期方法实现
@Override
public final synchronized void init() throws LifecycleException {if (!state.equals(LifecycleState.NEW)) {//new状态是最初加载时必须为NEWinvalidTransition(Lifecycle.BEFORE_INIT_EVENT);}try {setStateInternal(LifecycleState.INITIALIZING, null, false);initInternal();        //实际生命周期实现逻辑,由子类实现setStateInternal(LifecycleState.INITIALIZED, null, false);} catch (Throwable t) {handleSubClassException(t, "lifecycleBase.initFail", toString());}
}

通过init()的具体代码可以发现,LifecycleBase中主要就是设置了生命周期的状态,其中setStateInternal()除了设置了状态、校验了状态是否正确之外,还调用了上文提到的fireLifecycleEvent()响应了当前状态事件,触发了监听该事件的监听器监听到该事件的逻辑。由于不同子类(主要是不同容器)在初始化时所需要做的事不一样,所以initInternal()是真正被子类重载后做初始化的事情的方法。
    start()内部逻辑的特点和init()很相似,也是做了设置生命周期的状态,稍微复杂一些是需要:1.判断状态是否处于可以start()的阶段,不然就需要先init();2.是否失败需要stop()。

@Override
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)) {stop(); //失败直接终止} else if (!state.equals(LifecycleState.STARTING)) {invalidTransition(Lifecycle.AFTER_START_EVENT);} else {setStateInternal(LifecycleState.STARTED, null, false);}} catch (Throwable t) {handleSubClassException(t, "lifecycleBase.startFail", toString());}
}

可以看到,依旧有很多状态变更,和处理状态变更、发布状态变更事件的setStateInternal()的调用。

宏观来看各种容器生命周期的实际流程

在原理(一)我已经详细介绍了各种容器的配置、静态嵌套结构和各自的功能,铺垫了这么多,终于可以介绍各种容器是如果加载初始化的了。

    首先按照基本嵌套结构,如图,最开始需要先启动Server,不管是Tomcat独立部署包还是spring mvc中的嵌入式tomcat-embed包,都需要先调用Server.init(),然后调用Server.start()。实际上,tomcat中Server的标准实现是StandardServer,根据LifecycleBase中实现的init()和start()的代码,实际上会调用子类重载的initInternal()和startInternal()方法。在StandardServer的initInternal()和startInternal()方法中,会调用StandardServer类中的Service实例的init()和start()方法…另一个方面,在StandardServer的addService()方法也会调用添加的Service实例(实际是StandardService类)的start()方法。同样的逻辑适用于Service下的Engine容器。
    Engine以下的Host、Context、Wrapper略有不同,因为它们都实现自Container接口,继承了Container接口的标准实现ContainerBase。Container中将每一种容器的包含关系定义为父子关系,即Host是Engine类的Container child,使用这个Container[]来存储所有Host子容器。同理Host和Context、Context和Wrapper都是相同的关系。在ContainerBase中实现的startInternal()有:

Container children[] = findChildren();
List<Future<Void>> results = new ArrayList<>();
for (int i = 0; i < children.length; i++) {results.add(startStopExecutor.submit(new StartChild(children[i])));
}

需要特别注意的是,Container启动子容器的时候不一定是通过init()或者start()中调用相应子容器的生命周期函数。在容器的addChild方法中,也会调用子容器的start()方法,初始化加载和启动子容器,比如host的addChild(context)方法会调用context的start方法。
统一使用多线程执行调用child的start方法,这样各个容器都能按顺序初始化和启动。
    关于边界的情况,比如Wrapper部分,由于和spring mvc相关,会在spring mvc原理里面叙述。

本系列文章:
tomcat + spring mvc原理(一):tomcat原理综述和静态架构
tomcat + spring mvc原理(三):tomcat网络请求的监控与处理1
tomcat + spring mvc原理(四):tomcat网络请求的监控与处理2
tomcat + spring mvc原理(五):tomcat Filter组件实现原理
tomcat + spring mvc原理(六):tomcat WAR包的部署与加载

tomcat + spring mvc原理(二):tomcat容器初始化加载和启动相关推荐

  1. tomcat + spring mvc原理(六):tomcat WAR包的部署与加载

    tomcat + spring mvc原理(六):tomcat WAR包的部署与加载 前言 监控的启动原理 状态监听 部署项目 前言 单独部署的tomcat服务器在运行中,当开发人员或者运维人员将开发 ...

  2. tomcat + spring mvc 原理(一):tomcat原理综述和静态架构

    tomcat + spring mvc 原理(一):tomcat原理综述和静态架构 tomcat + spring mvc的运作模式 tomcat内部的基本容器构成 tomcat容器对应的外部配置 t ...

  3. 006-spring cloud gateway-GatewayAutoConfiguration核心配置-GatewayProperties初始化加载、Route初始化加载...

    一.GatewayProperties 1.1.在GatewayAutoConfiguration中加载 在Spring-Cloud-Gateway初始化时,同时GatewayAutoConfigur ...

  4. Spring MVC 原理探秘 - 容器的创建过程

    1.简介 在上一篇文章中,我向大家介绍了 Spring MVC 是如何处理 HTTP 请求的.Spring MVC 可对外提供服务时,说明其已经处于了就绪状态.再次之前,Spring MVC 需要进行 ...

  5. spring mvc原理_SpringBoot:认认真真梳理一遍自动装配原理

    点击上方"Java知音",选择"置顶公众号" 技术文章第一时间送达! 前言 Spring翻译为中文是"春天",的确,在某段时间内,它给Jav ...

  6. 一步一步手绘Spring MVC运行时序图(Spring MVC原理)

    相关内容: 架构师系列内容:架构师学习笔记(持续更新) 一步一步手绘Spring IOC运行时序图一(Spring 核心容器 IOC初始化过程) 一步一步手绘Spring IOC运行时序图二(基于XM ...

  7. Spring MVC 原理探秘 - 一个请求的旅行过程

    1.简介 在前面的文章中,我较为详细的分析了 Spring IOC 和 AOP 部分的源码,并写成了文章.为了让我的 Spring 源码分析系列文章更为丰富一些,所以从本篇文章开始,我将来向大家介绍一 ...

  8. Spring MVC原理及配置详解

    转载自 http://blog.csdn.net/jianyuerensheng/article/details/51258942 [Spring]Spring MVC原理及配置 1.Spring M ...

  9. 【Spring】Spring MVC原理及配置详解

    [Spring]Spring MVC原理及配置 1.Spring MVC概述: Spring MVC是Spring提供的一个强大而灵活的web框架.借助于注解,Spring MVC提供了几乎是POJO ...

最新文章

  1. 简洁高效的linux kfifo环形缓冲区
  2. CentOS6 vsftpd 安装及优化方法
  3. 循环GridView
  4. Android中文图混排时文图的居中对齐 FontMetrics以及自定义ImageSpan实现
  5. 玩转oracle 11g(33):无监听程序
  6. 解决计算治理问题,详解微众银行大数据平台中间件Linkis架构和应用
  7. 光复用技术中三种重要技术_【技术文章】X射线无损检测仪在锂电池行业中的重要应用...
  8. 骁龙cpu linux内核,高通骁龙888 SoC在Linux 5.12内核才被支持,以往怎么兼容的?
  9. 鼠标单击双击事件监听
  10. c语言程序设计第07章在线测,《C语言程序设计》第07章在线测试.doc
  11. 独立视频LED显示屏控制系统
  12. pg 快速造1000w测试数据
  13. windows 10 内置 OpenSSH客户端
  14. 输入电压=24V 输出电压=8V 1.5A TO-252-5 DCDC芯片推荐
  15. 360手机java手机管家软件_360手机管家最新版下载_360手机管家官方下载-太平洋下载中心...
  16. (生活篇)职场饭局生存法则
  17. 可见的轮廓线用虚线绘制_绘制视图时,可见的轮廓线用粗实线绘制,不可见的轮廓线用细虚线绘制 答案:√...
  18. 每天高并发超千万订单,滴滴的计价系统是如何构建的?
  19. M301H_JL九联-Hi3798MV310-当贝纯净桌面-卡刷固件包
  20. JetBrains 发布 2019 年 Java 调查报告

热门文章

  1. 【转载】UART流控
  2. 三项技术可以让自动驾驶更安全
  3. 谷歌浏览器(Chrome):前进后退清除缓存_掌握这几个浏览器快捷键,提高五倍工作效率。
  4. vue,uni-app算出两个时间相差的天数
  5. css3边框交替动画_利用 SVG 和 CSS3 实现有趣的边框动画
  6. mysql bi方案_《奥威Power-BI基于MySQL数据源制作报表》精彩回顾
  7. Segment Anything模型结构解读
  8. C# string中的copy()CopyTo()
  9. 正则表达式超全笔记!!这一篇就够了!!
  10. android 播放器评测,山灵M6新版评测 简谈山灵所有安卓播放器音质差异