javascript
SpringBoot 热部署神器快速重启的秘密!
今天咱們來聊聊這個熱部署神器?spring-boot-devtools?的運行原理,看看它是怎么用這個 ClassLoader ?來實現快速重啟,幫我們節省時間的!😝
文章概要
文章的主旋律如下👇
spring.factories
我們直接打開 spring-boot-devtools 源碼 ,找到 spring.factories 文件:
我們一般都本地開發調試的,所以就直接看這個 LocalDevToolsAutoConfiguration 類啦😋
LocalDevToolsAutoConfiguration
可以看到核心點在 重啟和重載 👇
主角👇
我們先來看看這個 重啟 中有什么叭😄
重啟原理介紹
大概這么一個思路👇 下面就跟著源碼分析啦😄(文末有源碼重啟要點流程圖)
RestartConfiguration
有這么些方法👇
從名字上分析,這兩個方法應該是重點,邏輯上應該是 有一個 watcher 在盯著 classpath ,如果有變動的話,就觸發這個 ClassPathChangedEvent 事件 😝
那么看看這個 watcher 叭 😄
ClassPathFileSystemWatcher
可以看到這里就創建了這個 ClassPathFileSystemWatcher 類 👇
這里我們注意到它實現了三個接口,經過前面 Spring 文章的學習,咱們知道第一步就該看啥了😄
根據類的初始化,先看看有 static 相關的代碼沒,接著看 構造器 ,最后就來到這個初始化方法 afterPropertiesSet 啦😄
這里沒有 static 方法,構造器也很簡單,就是獲取 FileSystemWatcherFactory ?,ClassPathRestartStrategy 和 監視的文件路徑,那么就看看 afterPropertiesSet 寫了什么叭 👇
ClassPathFileChangeListener
這個也不復雜,就監聽到文件改變后,發布事件 ClassPathChangedEvent
FileSystemWatcher
接著就是這個 start 方法啦👇
很明顯就是開啟一個線程,那么咱們來看看線程中到底在 run 什么🐷
找到這個任務類 Watcher 👇
可以發現它的任務就是一直 scan ,pollInterval 默認是 1s ,quietPeriod 默認是 0.4s
意思是每次輪詢的時間是 1s ,包含中間休息的 0.4s ,休息事件是來確認文件在這個期間沒有再次被改動。
改動了的話會回調 FileChangeListener 的 onChange ,對應我們上面的這個 ClassPathFileChangeListener ,會去發布事件 ClassPathChangedEvent 😋
ApplicationListener
繞了一大圈,終于描述完了這個監視器 ClassPathFileSystemWatcher ,同時,我們也得把目光移到這個RestartConfiguration 的第二個核心 監聽器 👇
如圖所示,這個方法的作用就是重啟應用 restart
重啟應用
重啟的過程中呢,包括兩個步驟,第一步 stop ,第二步 start
stop 部分就是毀滅這些東西了,這里也藏了很多細節,有很多并發相關的知識點 😋
比如
一. ReentrantLock ?是寫在 try catch 的里面還是外面?
二. 循環里的 rootContexts 其實是 CopyOnWriteArrayList 類型的
三. 通過強制的 OOM 來清除所有的 軟/弱引用 (😱 還有這種操作的!)
在 start 的過程中,是通過創建這個重啟線程 RestartLauncher 來實現的,可以發現該類的任務就是找到 mainclass 并調用 main 方法,完成重啟。
而在這個過程中,就涉及到這個 classloader 啦。
ClassLoader
細心的小伙伴可以發現上面這行代碼中,調用到了這個 ClassLoader ,這個 getContextClassLoader() 是屬于 Thread 類的,通過它可以獲取到當前線程上下文的 ClassLoader 。
Class.forName(this.mainClassName,?false,?getContextClassLoader());在創建這個 RestartLauncher 線程時,就已經將咱們這個 RestartClassLoader ?給傳進來了。
重啟時,就直接通過 RestartClassLoader ?去找到 main 方法,完成重啟。
很明顯這里 破壞了雙親委派機制,先從自身查找,沒有的話再去父類查找
這里 業務代碼 都被 RestartClassLoader 加載了,而每次重啟都會重新創建這個 RestartClassLoader ?,然后去加載業務代碼 🐖 (通過傳進來的 URL ?可以發現)
那么到此,這個 重啟 的過程就完成了。
差點忘了,這里還有個默認的監視范圍🐷
監視策略
如下圖👇 默認策略中,這些路徑下的文件變化不被檢測
image-20210920230435492可通過配置修改
spring.devtools.restart.exclude=static/**,public/**總結
通過閱讀源碼,我們知道了 spring-boot-devtools 是通過自定義 RestartClassLoader ?來加載業務代碼,并在重啟時銷毀它,再重新創建,進而重新獲取代碼,實現這個快速重啟的。
而其他 jar 包等由另外的 ClassLoader ?加載,不受影響。
同時,也可以看到 Spring 事件機制 無處不在的身影,還有各種初始化的操作,以及線程,并發,鎖在重啟過程中的使用,這些就需要小伙伴們打開源碼自身感受了,如 守護線程,ReentrantLock ,CopyOnWriteArrayList ,CountDownLatch ,甚至 OOM 都能這么用!
還有 重啟 原來就是 反射調用 main 方法 呀🐷
重啟過程源碼要點
本文就分享到這里啦,喜歡的朋友點個贊再走哦
往期推薦Spring 事務失效的 8 種場景!
實戰,實現冪等的8種方案!
絕絕子,畫框架圖就用這個工具
總結
以上是生活随笔為你收集整理的SpringBoot 热部署神器快速重启的秘密!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: printstream_Java Pri
- 下一篇: SpringBoot + Shardin