芋道 Spring Boot 熱部署入門

點擊上方“芋道源碼”,選擇“設爲星標

做積極的人,而不是積極廢人!

源碼精品專欄

 

摘要: 原創出處 http://www.iocoder.cn/Spring-Boot/hot-swap/ 「芋道源碼」歡迎轉載,保留摘要,謝謝!

  • 1. 概述

  • 2. spring-boot-devtools

  • 3. IDEA 熱部署

  • 4. Jrebel

  • 666. 彩蛋


1. 概述

在日常開發中,我們需要經常修改 Java 代碼,手動重啓項目,查看修改後的效果。如果在項目小時,重啓速度比較快,等待的時間是較短的。但是隨着項目逐漸變大,重啓的速度變慢,等待時間 1-2 min 是比較常見的。

這樣就導致我們開發效率降低,影響我們的下班時間,哈哈哈~那麼是否有方式能夠實現,在我們修改完 Java 代碼之後,能夠不重啓項目呢?

答案是有的,通過熱部署的方式。並且實現的方式還是非常多,艿艿在本文就會爲胖友一一展示。

旁白君:嚴格來說,應該叫 HotSwap 的方式,翻譯成中文會有熱部署、熱更新、熱替換、熱加載等等多種。這裏,我們就採用大家可能說的比較多的翻譯,熱部署

爲了演示方便,胖友可以參考 lab-48-demo 項目,搭建一個簡單的 Spring Boot 項目,提供了一個簡單的 HTTP API。如下圖所示:

友情提示:不要直接通過克隆 https://github.com/YunaiV/SpringBoot-Labs 來使用該項目,實在太大了!

並且,我們下面我們所有的演示,都是在宇宙無敵 Java 開發工具 IDEA 中進行。

2. spring-boot-devtools

spring-boot-devtools 是 Spring Boot 提供的開發者工具,它會監控當前應用所在的 classpath 下的文件發生變化,進行自動重啓

注意,spring-boot-devtools沒有採用熱部署的方式,而是一種較快的重啓方式。其官方文檔解釋如下:

FROM 《Spring Boot 2.X 中文文檔 —— 開發者工具》

Spring Boot 通過使用兩個類加載器來提供了重啓技術。

  • 不改變的類(例如,第三方 jar)被加載到 base 類加載器中。

  • 經常處於開發狀態的類被加載到 restart 類加載器中。

當應用重啓時,restart 類加載器將被丟棄,並重新創建一個新的。這種方式意味着應用重啓比冷啓動要快得多,因爲省去 base 類加載器的處理步驟,並且可以直接使用。

如果您覺得重啓還不夠快,或者遇到類加載問題,您可以考慮如 ZeroTurnaround 的 JRebel 等工具。他們是通過在加載類時重寫類來加快重新加載。

在項目中,我們需要在 pom.xml 中,引入 spring-boot-devtools 依賴如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional> <!-- 可選 -->
</dependency>

2.1 演示

下面,我們來演示下 spring-boot-devtools 的使用。

① Run 或者 Debug 運行 Spring Boot 應用。

使用瀏覽器,訪問 http://127.0.0.1:8080/demo/echo 接口,返回結果爲 "echo"

② 修改 DemoController 的 #echo() 方法,設置返回值爲 "none"

【關鍵】 我們現在僅僅需要修改了 Java 代碼,需要重新編譯下代碼。點擊 IDEA 的菜單 Build -> Build Project手動進行編譯。如下圖所示:

友情提示:如果胖友嫌棄鼠標操作太慢,可以使用 Build Project 的快捷鍵:

  • Mac:Command + F9

  • Windows:Ctrl + F9

此時,IDEA 控制檯會看到 Spring Boot 重新啓動的日誌如下:

2020-02-09 09:22:52.082  INFO 36495 --- [      Thread-10] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.4.RELEASE)

2020-02-09 09:22:52.195  INFO 36495 --- [  restartedMain] cn.iocoder.demo03.Demo03Application      : Starting Demo03Application on MacBook-Pro-8 with PID 36495 (/Users/yunai/Downloads/demo03/target/classes started by yunai in /Users/yunai/Downloads/demo03)
2020-02-09 09:22:52.195  INFO 36495 --- [  restartedMain] cn.iocoder.demo03.Demo03Application      : No active profile set, falling back to default profiles: default
2020-02-09 09:22:52.335  INFO 36495 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2020-02-09 09:22:52.336  INFO 36495 --- [  restartedMain] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2020-02-09 09:22:52.336  INFO 36495 --- [  restartedMain] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.30]
2020-02-09 09:22:52.342  INFO 36495 --- [  restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2020-02-09 09:22:52.342  INFO 36495 --- [  restartedMain] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 145 ms
2020-02-09 09:22:52.382  INFO 36495 --- [  restartedMain] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-02-09 09:22:52.409  INFO 36495 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2020-02-09 09:22:52.418  INFO 36495 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-02-09 09:22:52.419  INFO 36495 --- [  restartedMain] cn.iocoder.demo03.Demo03Application      : Started Demo03Application in 0.244 seconds (JVM running for 169.162)
2020-02-09 09:22:52.420  INFO 36495 --- [  restartedMain] .ConditionEvaluationDeltaLoggingListener : Condition evaluation unchanged
  • ???? 所以 spring-boot-devtools 真的不是熱部署,而是更快的重啓方式。

使用瀏覽器,再次訪問 http://127.0.0.1:8080/demo/echo 接口,返回結果爲 "none",成功!

咳咳咳,下面我們來講解下自動編譯。艿艿自己嘗試了,親測失敗。例如說 《IDEA 配置 Spring Boot 熱更新,無需手動按 ctrl+F9》 文章。看了下評論,貌似其它人也存在失敗的情況。

反正這裏也寫下步驟,胖友可以自己嘗試一波~萬一成功了,請一定留言,我好找找具體原因。

③ 可能有胖友會覺得手動 Build Project 有點麻煩,IDEA 還提供的自動編譯的選項。設置方式,點擊 IDEA 的菜單 IntelliJ IDEA -> Preference...,然後選擇 Compiler 選項卡,將 Build project automatically 勾選上。如下圖所示:

友情提示:注意,Build project automatically 後面的一行提示,自動編譯僅在項目不處於運行,或者處於 Debug 運行中時,纔會自動生效。

所以一定要 Debug 運行 Spring Boot 項目。具體的效果,胖友自己重複 ① ② 兩個步驟,自己嘗試下。

另外,網上我們會看到教程,建議將 compiler.automake.allow.when.app.running 勾選上。

  • 原因是,自動編譯在 Running 運行中默認是不生效的,通過勾選上 compiler.automake.allow.when.app.running,允許在 Running 運行中也生效。

  • 個人建議的話,不要勾選。如果 Running 運行中修改了代碼,也會導致熱部署,不太合適。如果真要熱部署,使用 Debug 運行項目更合理。

2.2 結論

因爲 spring-boot-devtools 提供的本質是重啓的方式,所以還是會存在我們在文章開頭所提到的問題。不過不要慌,實際上 IDEA 自帶了熱部署的方式,畢竟是宇宙第一 Java 開發工具,吹爆就完事了。

3. IDEA 熱部署

友情提示:如果胖友看了「2. spring-boot-devtools」小節,並進行了相關操作,請全部復原,特別是去掉 spring-boot-devtools 依賴。

IDEA 提供了 HotSwap 插件,可以實現真正的熱部署。如下圖所示:

3.1 演示

下面,我們來演示下 HotSwap 插件的使用。

① Run 或者 Debug 運行 Spring Boot 應用。

使用瀏覽器,訪問 http://127.0.0.1:8080/demo/echo 接口,返回結果爲 "echo"

② 修改 DemoController 的 #echo() 方法,設置返回值爲 "none"

【關鍵】 我們現在僅僅需要修改了 Java 代碼,需要重新編譯下代碼。點擊 IDEA 的菜單 Build -> Build Project手動進行編譯。如下圖所示:

友情提示:如果胖友嫌棄鼠標操作太慢,可以使用 Build Project 的快捷鍵:

  • Mac:Command + F9

  • Windows:Ctrl + F9

此時,我們在 IDEA 中可以看修改的類被重載的提示。如下圖所示:

使用瀏覽器,再次訪問 http://127.0.0.1:8080/demo/echo 接口,返回結果爲 "none",成功!

③ 嘗試將 Build project automatically 勾選上,希望實現自動編譯,再搭配上 HotSwap 插件的熱部署,豈不是更香?!

結果失敗,和「2.1 演示」出現一樣的問題,略微蛋疼。

這裏我們來換一種方式,也能實現自動編譯。操作步驟如下圖:

  • 要注意,需要焦點從 IDEA 離開。例如說,在我們修改完接口的代碼之後,可能會切換到瀏覽器或者 Postman 對該接口進行測試,此時 IDEA 就會自動更新代碼和資源,進行熱部署。

現在,我們來 修改 DemoController 的 #echo() 方法,設置返回值爲 "todo"

切換到瀏覽器再趕緊切換到 IDEA 中,以達到 IDEA 失去焦點的效果。我們在 IDEA 中可以看修改的類被重載的提示。如下圖所示:

使用瀏覽器,再次訪問 http://127.0.0.1:8080/demo/echo 接口,返回結果爲 "todo",成功!

3.2 結論

艿艿個人的喜好的話,使用 IDEA 熱部署爲主,通過快捷鍵來手動編譯。畢竟,我是一個“主動”的人,默默開一波車,哈哈哈。

當然,不是說自動編譯有什麼不好,只是每個人的選擇。具體的,胖友可以都試試,尋找一個自己喜歡的方式。

4. Jrebel

Jrebel 是比較有名的一款 Java 熱部署插件。

因爲 IDEA 自帶的 HotSwap 插件已經能夠滿足我們的熱部署的訴求,所以本文也不多嗶嗶啥了。真的感興趣的胖友,可以看看《IDEA JRebel 插件熱部署(史上最全)》文章。不過,必要性不大,嘿嘿。

666. 彩蛋

至此,我們已經完成了 Spring Boot 熱部署的入門。咳咳咳,相信胖友們通過使用熱部署,一定能提高開發效率,寫更多的代碼,出更多的 BUG,加更多的班。

沒毛病,奧利給,幹就完事了!



歡迎加入我的知識星球,一起探討架構,交流源碼。加入方式,長按下方二維碼噢

已在知識星球更新源碼解析如下:

最近更新《芋道 SpringBoot 2.X 入門》系列,已經 20 餘篇,覆蓋了 MyBatis、Redis、MongoDB、ES、分庫分表、讀寫分離、SpringMVC、Webflux、權限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能測試等等內容。

提供近 3W 行代碼的 SpringBoot 示例,以及超 4W 行代碼的電商微服務項目。

獲取方式:點“在看”,關注公衆號並回復 666 領取,更多內容陸續奉上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章