写点什么

Tomcat 实现热部署、热加载原理解析,线程池底层实现原理

作者:Java高工P7
  • 2021 年 11 月 10 日
  • 本文字数:2352 字

    阅读完需:约 8 分钟

.scheduleWithFixedDelay(


// 要周期性执行的 Runnable


new ContainerBackgroundProcessor(),


//第一次执行延迟多久


backgroundProcessorDelay,


// 之后每次执行间隔多久


backgroundProcessorDelay,


// 时间单位


TimeUnit.SECONDS);


任务类 ContainerBackgroundProcessor 是 ContainerBase 的内部类,ContainerBase 是所有容器组件的基类。


ContainerBackgroundProcessor




protected class ContainerBackgroundProcessor implements Runnable {


@Override


public void run() {


// 入参"宿主类"实例


processChildren(ContainerBase.this);


}


protected void processChildren(Container container) {


try {


// 1. 调用当前容器的 backgroundProcess


container.backgroundProcess();


// 2. 遍历所有子容器,递归调用 processChildren


// 这样当前容器的子孙都会被处理


Container[] children = container.findChildren();


for (int i = 0; i < children.length; i++) {


// 容器基类有个变量叫做 backgroundProcessorDelay


// 如果大于 0,表明子容器有自己的后台线程


// 无需父容器来调用它的 processChildren 方法


if (children[i].getBackgroundProcessorDelay() <= 0) {


processChildren(children[i]);


}


}


} catch (Throwable t) { ... }


processChildren 把“宿主类”,即 ContainerBase 的类实例当成参数传给了 run 方法。


而在 processChildren 方法里,就做了两步:调用当前容器的 backgroundProcess 方法,以及递归调用子孙的 backgroundProcess 方法。请你注意 backgroundProcess 是 Container 接口中的方法,也就是说所有类型的容器都可以实现这个方法,在这个方法里完成需要周期性执行的任务。


这样只需在顶层容器 Engine 中启动一个后台线程,则该线程不但会执行 Engine 容器的周期性任务,还会执行所有子容器的周期性任务。

backgroundProcess 方法

上述代码都是在基类 ContainerBase 实现,具体容器类需要做什么呢?


  • 若有周期性任务,就实现 backgroundProcess

  • 若没有,则复用基类 ContainerBase 的方法

ContainerBase#backgroundProcess

public void backgroundProcess() {


// 1.执行容器中 Cluster 组件的周期性任务


Cluster cluster = getClusterInternal();


if (cluster != null) {


cluster.backgroundProcess();


}


// 2.执行容器中 Realm 组件的周期性任务


Realm realm = getRealmInternal();


if (realm != null) {


realm.backgroundProcess();


}


// 3.执行容器中 Valve 组件的周期性任务


Valve current = pipeline.getFirst();


while (current != null) {


current.backgroundProcess();


current = current.getNext();


}


// 4. 触发容器的"周期事件",Host 容器的监听器 HostConfig 就靠它来调用


fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null);


}


不仅每个容器可以有周期性任务,每个容器中的其他通用组件,比如跟集群管理有关的 Cluster 组件、跟安全管理有关的 Realm 组件都可以有自己的周期性任务。


容器之间的链式调用是通过 Pipeline-Valve 机制实现的,容器中的 Valve 也可以有周期性任务,并且被 ContainerBase 统一处理。


在 backgroundProcess 方法的最后,还触发了容器的“周期事件”。“周期事件”是什么呢?


它跟生命周期事件一样,是一种扩展机制,可以这样理解:


又一段时间过去了,容器还活着,你想做点什么吗?


如果你想做点什么,就创建一个监听器来监听这个“周期事件”,事件到了我负责调用你的方法。


总之,有了 ContainerBase 中的后台线程和 backgroundProcess 方法,各种子容器和通用组件不需要各自弄一个后台线程来处理周期性任务。


Tomcat 热加载


========================================================================


有了 ContainerBase 的周期性任务处理“框架”,具体容器子类只需实现自己的周期性任务。


Tomcat 的热加载,就实现在 Context 容器。

Context#backgroundProcess

StandardContext 实现类中:


@Override


public void backgroundProcess() {


if (!getState().isAvailable())


return;


// WebappLoader 周期性检查


// WEB-INF/classes、WEB-INF/lib 目录下的类文件是否有更新


Loader loader = getLoader();


if (loader != null) {


loader.backgroundProcess();


}


// Session 管理器周期性检查是否有 Session 过期


Manager manager = getManager();


if (manager != null) {


manager.backgroundProcess();


}


// 周期性检查静态资源是否有更新


WebResourceRoot resources = getResources();


if (resources != null) {


resources.backgroundProcess();


}


super.backgroundProcess();


}


WebappLoader 是如何实现热加载的呢?


关键是调用 Context#reload 方法:



《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


止和销毁 Context 容器及其所有子容器(Wrapper),即 Wrapper 里的 Servlet 实例也被销毁


  • 停止和销毁 Context 容器关联的 Listener 和 Filter

  • 停止和销毁 Context 下的 Pipeline 和各种 Valve

  • 停止和销毁 Context 的类加载器,以及类加载器加载的类文件资源


启动 Context 容器,在这个过程中会重新创建前面四步被销毁的资源。


在这个过程中,类加载器发挥着关键作用。一个 Context 容器对应一个类加载器,类加载器在销毁的过程中会把它加载的所有类也全部销毁。Context 容器在启动过程中,会创建一个新的类加载器来加载新的类文件。


在 Context 的 reload 方法里,并没有调用 Session 管理器的 destroy 方法,也就是说这个 Context 关联的 Session 是没有销毁的。


Tomcat 热加载默认是关闭的,需在 conf 目录下的 context.xml 文件中设置 reloadable 参数开启:


<Context reloadable="true"/>


Tomcat 热部署


========================================================================


跟热加载的本质区别是:


热部署会重新部署 Web 应用,原 Context 对象会被整个被销毁,因此该 Context 所关联一切资源都会被销毁,包括 Session。


Tomcat 热部署由哪个容器实现呢?

用户头像

Java高工P7

关注

还未添加个人签名 2021.11.08 加入

还未添加个人简介

评论

发布
暂无评论
Tomcat实现热部署、热加载原理解析,线程池底层实现原理