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种场景,太坑了

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

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…

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

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

Spring Boot Admin,贼好使!

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

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,那感觉只有两个字“真香…

SpringBoot + ShardingSphere 秒级分库分表!

Spring Boot 作为主流微服务框架,拥有成熟的社区生态。市场应用广泛,为了方便大家,整理了一个基于spring boot的常用中间件快速集成入门系列手册,涉及RPC、缓存、消息队列、分库分表、注册中心、分布式配置等常用开源组件&#xf…

git reset, git checkout, git revert 区别 (译)

博客原文地址: http://blog.mexiqq.com/index.php/archives/3/题记:团队中大多数成员使用 sourceTree 和 github 两款 git 工具,然而大家对于图形化工具提供的 reset,checkout,revert 功能点并不是很了解,甚至于混淆,然后凭借猜测去使用。功夫…

Redis笔记之基本数据结构 动态字符串SDS

简单动态字符串 传统上的C语言的字符串表示是以空字符结尾的字符数组(C字符串),redis自己实现一个动态字符串(SDS),两者之间的区别以及使用SDS的好处有: 结构不同。C字符串以空字符结尾的字符…

扯一把 Spring 的三种注入方式,到底哪种注入方式最佳?

1. 实例的注入方式首先来看看 Spring 中的实例该如何注入,总结起来,无非三种:属性注入set 方法注入构造方法注入我们分别来看下。1.1 属性注入属性注入是大家最为常见也是使用最多的一种注入方式了,代码如下:Service p…

Redis笔记之基本数据结构 链表

链表 链表具有空间存储不连续,增删节点快的优点,因此redis在列表键、发布与订阅、慢查询、监视器等使用了链表作为底层实现。由于C语言中没有内置的链表实现,因此redis自己进行了实现。 双向链表。每个listtNode都有perv和next指针&#x…

SpringCloud组件:Ribbon负载均衡策略及执行原理!

大家好,我是磊哥。今天我们来看下微服务中非常重要的一个组件:Ribbon。它作为负载均衡器在分布式网络中扮演着非常重要的角色。本篇主要内容如下:在介绍 Ribbon 之前,不得不说下负载均衡这个比较偏僻的名词。为什么说它偏僻了&…