SpringBoot 热部署神器快速重启的秘密!

今天咱们来聊聊这个热部署神器 spring-boot-devtools 的运行原理,看看它是怎么用这个 ClassLoader  来实现快速重启,帮我们节省时间的!😝

文章概要

文章的主旋律如下👇

834f428efa34841f25715de6386a5fb5.png

spring.factories

我们直接打开 spring-boot-devtools 源码 ,找到 spring.factories 文件:

87694a012a21af4a7b3a202d13604204.png

我们一般都本地开发调试的,所以就直接看这个 LocalDevToolsAutoConfiguration 类啦😋

LocalDevToolsAutoConfiguration

可以看到核心点在 重启和重载 👇

7d3d98255f210362fe4a8798b0bdd8f2.png

主角👇

777b8454a399395a8c375bd803e15f59.png

我们先来看看这个 重启 中有什么叭😄

重启原理介绍

大概这么一个思路👇 下面就跟着源码分析啦😄(文末有源码重启要点流程图

a2b60983768ce46d22f674c72068b85d.png

RestartConfiguration

有这么些方法👇

ee9b710a839fe086532c9428a8c5aaa0.png

从名字上分析,这两个方法应该是重点,逻辑上应该是 有一个 watcher 在盯着 classpath ,如果有变动的话,就触发这个 ClassPathChangedEvent 事件 😝

那么看看这个 watcher 叭 😄

ClassPathFileSystemWatcher

e33970c26d33269a78fe3f3c3d67d5c6.png

可以看到这里就创建了这个 ClassPathFileSystemWatcher 类 👇

39186be8772902981978d88caa49bf95.png

这里我们注意到它实现了三个接口,经过前面 Spring 文章的学习,咱们知道第一步就该看啥了😄

根据类的初始化,先看看有 static 相关的代码没,接着看 构造器 ,最后就来到这个初始化方法 afterPropertiesSet 啦😄

这里没有 static 方法,构造器也很简单,就是获取 FileSystemWatcherFactory  ,ClassPathRestartStrategy 和 监视的文件路径,那么就看看 afterPropertiesSet 写了什么叭 👇

c21944f2f3fd6002ab9536732745485d.png

ClassPathFileChangeListener

这个也不复杂,就监听到文件改变后,发布事件 ClassPathChangedEvent

5ee65040431dd8c772b4a737d38933bd.png

FileSystemWatcher

接着就是这个 start 方法啦👇

很明显就是开启一个线程,那么咱们来看看线程中到底在 run 什么🐷

8796cc476b1431b0e8bca602706a0807.png

找到这个任务类 Watcher 👇

aeb2e4aa29e2c501e2a76b3eae3912ec.png

可以发现它的任务就是一直 scanpollInterval 默认是 1squietPeriod 默认是 0.4s

意思是每次轮询的时间是 1s ,包含中间休息的 0.4s ,休息事件是来确认文件在这个期间没有再次被改动。

改动了的话会回调 FileChangeListeneronChange ,对应我们上面的这个 ClassPathFileChangeListener ,会去发布事件 ClassPathChangedEvent 😋

ApplicationListener

绕了一大圈,终于描述完了这个监视器 ClassPathFileSystemWatcher ,同时,我们也得把目光移到这个RestartConfiguration 的第二个核心 监听器 👇

如图所示,这个方法的作用就是重启应用 restart

98743815fc834f9223d6e65820f91ad1.png

重启应用

重启的过程中呢,包括两个步骤,第一步 stop ,第二步 start

stop 部分就是毁灭这些东西了,这里也藏了很多细节,有很多并发相关的知识点 😋

比如

一. ReentrantLock  是写在 try catch 的里面还是外面?

二. 循环里的 rootContexts 其实是 CopyOnWriteArrayList 类型的

三. 通过强制的 OOM 来清除所有的 软/弱引用 (😱 还有这种操作的!)

e0b5e339063009ae4502a416980e1cbd.png

start 的过程中,是通过创建这个重启线程 RestartLauncher 来实现的,可以发现该类的任务就是找到 mainclass 并调用 main 方法,完成重启。

0c9ff98ba0cef6a0dcdd909c649f98d4.png

而在这个过程中,就涉及到这个 classloader 啦。

ClassLoader

细心的小伙伴可以发现上面这行代码中,调用到了这个 ClassLoader ,这个 getContextClassLoader() 是属于 Thread 类的,通过它可以获取到当前线程上下文的 ClassLoader

Class.forName(this.mainClassName, false, getContextClassLoader());

在创建这个 RestartLauncher 线程时,就已经将咱们这个 RestartClassLoader  给传进来了。

072fa51f62753674a2cea687d9e88b97.png

8bea2229d939136d8376265538d30e43.png

重启时,就直接通过 RestartClassLoader  去找到 main 方法,完成重启。

f522f2d6cc8358705bd9231fcd2ebd6b.png

很明显这里 破坏了双亲委派机制,先从自身查找,没有的话再去父类查找

这里 业务代码 都被 RestartClassLoader 加载了,而每次重启都会重新创建这个 RestartClassLoader  ,然后去加载业务代码 🐖 (通过传进来的 URL  可以发现)

那么到此,这个 重启 的过程就完成了。

差点忘了,这里还有个默认的监视范围🐷

监视策略

如下图👇 默认策略中,这些路径下的文件变化不被检测

d75adb3b7b70671250fc6de844759985.png
image-20210920230435492

可通过配置修改

spring.devtools.restart.exclude=static/**,public/**

总结

通过阅读源码,我们知道了 spring-boot-devtools 是通过自定义 RestartClassLoader  来加载业务代码,并在重启时销毁它,再重新创建,进而重新获取代码,实现这个快速重启的。

而其他 jar 包等由另外的 ClassLoader  加载,不受影响。

同时,也可以看到 Spring 事件机制 无处不在的身影,还有各种初始化的操作,以及线程,并发,锁在重启过程中的使用,这些就需要小伙伴们打开源码自身感受了,如 守护线程ReentrantLockCopyOnWriteArrayListCountDownLatch ,甚至 OOM 都能这么用!

还有 重启 原来就是 反射调用 main 方法 呀🐷

重启过程源码要点

96a4f9c25ee5f2db0109523de2c3e601.png

7fcaa0e76a03d283a390198223a22714.png

本文就分享到这里啦,喜欢的朋友点个赞再走哦

f47dc7c38480b60de84eb90cfb99e245.gif

往期推荐

cf82cf171df6faff8c6e2b566953a372.png

Spring 事务失效的 8 种场景!


d9be9b3b1da1e3e30fac74c197316645.png

实战,实现幂等的8种方案!


d984027911bcab005d3c4ea6ac6114e7.png

绝绝子,画框架图就用这个工具


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/544366.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机操作系统 内存_计算机内存的类型| 操作系统

计算机操作系统 内存什么是记忆? (What is Memory?) The essential component of the computer is its Memory. It is assembled on the motherboard as it is a storage device used for storing data and instructions for performing a task on the system. 计算…

关于 java 实现 语音朗读

最近有个java项目要实现 一个 java语音朗读的功能,百度了半天 没有现成的 。也是一头雾水。没具体思路。。。。。大体上总结了下网上的资料 1.java 实现起来 比c或者vb 能麻烦点,或者是这个功能用其他语言完成 然后整合到java 项目里面去!2.…

查询MySQL字段注释的 5 种方法!

作者 | 磊哥来源 | Java中文社群(ID:javacn666)转载请联系授权(微信ID:GG_Stone)很多场景下,我们需要查看 MySQL 中表注释,或者是某张表下所有字段的注释,所以本文就来盘…

聊聊索引失效的10种场景,太坑了

前言今天我接着上一期数据库的话题,更进一步聊聊索引的相关问题,因为索引是大家都比较关心的公共话题,确实有很多坑。不知道你在实际工作中,有没有遇到过下面的这两种情况:明明在某个字段上加了索引,但实际…

python insert_Python列表| 带示例的insert()方法

python insertlist.insert()方法 (list.insert() Method) insert() is an inbuilt method in python, which is used to add an element /item at specified index to the list. insert()是python中的内置方法,用于将指定索引处的元素/ item添加到列表中。 insert(…

Java中的main方法

2019独角兽企业重金招聘Python工程师标准>>> 在一个Java应用程序中,通常程序的入口是一个main方法,它被声明为公有静态方法,参数是一个字符串数组,返回值为Void类型。这个方法有许多值得研究的地方,今天就来…

约瑟夫环问题(C++)

问题描述 首先,说明一下这个问题是研究生期间c课的综合作业,本来有好多选择但最后还是选择了约瑟夫环问题。下面是约瑟夫环的问题描述以及设计要求: 约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人&…

实战!工作中常用到哪些设计模式

前言 大家好,我是捡田螺的小男孩。平时我们写代码呢,多数情况都是流水线式写代码,基本就可以实现业务逻辑了。如何在写代码中找到乐趣呢,我觉得,最好的方式就是:使用设计模式优化自己的业务代码。今天跟大家…

什么是bcd码数据传输通讯_传输障碍| 数据通讯

什么是bcd码数据传输通讯传输障碍 (Transmission Impairment) In the data communication system, analog and digital signals go through the transmission medium. Transmission media are not ideal. There are some imperfections in transmission mediums. So, the signa…

Spring boot项目(问答网站)之timeline的推拉两种模式

Timeline介绍 所谓timeline就是当用户打开主页看到的随着时间轴发生的一系列时间的整合,主要包含: 关注用户的最新动态热门推荐广告推荐整合等等. 推、拉模式 推模式: 当一个用户关注了或者评论了一个问题或用户,触发事件&…

Bean放入Spring容器,你知道几种方式?

作者:三尺微命 一介书生来源:blog.csdn.net/weixin_43741092/article/details/120176466我们知道平时在开发中使用Spring的时候,都是将对象交由Spring去管理,那么将一个对象加入到Spring容器中,有哪些方式呢&#xff…

KMP POJ 2752 Seek the Name, Seek the Fame

题目传送门 1 /*2 题意:求出一个串的前缀与后缀相同的字串的长度3 KMP:nex[]就有这样的性质,倒过来输出就行了4 */5 /************************************************6 * Author :Running_Time7 * Created Time :2015-8-1…

c语言 函数的参数传递示例_C ++中带有示例的nearint()函数

c语言 函数的参数传递示例C 附近的int()函数 (C nearbyint() function) nearbyint() function is a library function of cmath header, it is used to round the given value to an integral value based on the specified direction by fegetround() function. It accepts a …

Spring boot项目(问答网站)之Python学习基础篇

简介 当问答网站基本框架搭建完毕之后需要一些初始的数据来进行填充,因此选用Python爬虫的方式,从网上截取一些资料信息(当然是自己做项目使用,非商用)放入到项目网站上面。这篇主要是关于Python基础知识的学习笔记。…

Spring Boot Admin,贼好使!

作者 | 磊哥来源 | Java中文社群(ID:javacn666)转载请联系授权(微信ID:GG_Stone)Spring Boot Admin(SBA)是一个开源的社区项目,用于管理和监控 Spring Boot 应用程序。应…

适用于各种列表操作的Python程序

Here, we are implementing a python program for various list operations, following operations are being performed in the list, 在这里,我们正在为各种列表操作实现python程序,正在列表中执行以下操作, Declaring an integer list 声…

一个障碍,就是一个超越自我的契机

一个障碍,就是一个新的已知条件,只要愿意,任何一个障碍,都会成为一个超越自我的契机。 有一天,素有森林之王之称的狮子,来到了 天神面前:"我很感谢你赐给我如此雄壮威武的体格、如此强大无…

JAVA基础之容器基础内容

Java Collections框架 Java Collections框架中包含了大量的集合接口以及这些接口的实现类和操作它们的方法,具体包含了Set(集合)、List(列表)、Map(键值对)、Queue(队列)、Stack(栈)等,其中List、Set、Queue、Stack都继承了Collection接口。…

更快的Maven构建工具mvnd和Gradle哪个性能更好?

作者 | 磊哥来源 | Java中文社群(ID:javacn666)转载请联系授权(微信ID:GG_Stone)Maven 作为经典的项目构建工具相信很多人已经用很久了,但如果体验过 Gradle,那感觉只有两个字“真香…

页面访问的常见错误码解析

200 OK 一切正常301 Moved Permanently 客户请求的文档在其他地方,新的URL在Location头中给出,浏览器应该自动地访问新的URL。 302 Found 类似于301,但新的URL应该被视为临时性的替代,而不是永久性的。注意,在HTT…