SpringBoot魔法堂:應用熱部署實踐與原理淺析

前言

後端開發的同學想必每天都在重複經歷着修改代碼、執行代碼編譯,等待……重啓Tomcat服務,等待……最後測試發現還是有bug,然後上述流程再來一遍(我聽不見)😦
能不能像前端開發的同學那樣,修改代碼保存文件後自動編譯、重新加載應用呢?Spring Boot給了我們一個大大的Yes!
本文我們就一起來探索Spring Boot的熱部署功能提升開發效率吧!

長話短說

熱部署作爲開發階段的特性,由spring-boot-devtools模塊提供,用於在修改類、配置文件和頁面等靜態資源後,自動編譯Spring Boot應用和加載應用和頁面靜態資源,從而提高開發流程自動化程度提升開發效率。
那麼第一步當然是在pom.xml中添加配置:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-devtools</artifactId>
  <option>true</option>
</dependency>

<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      <configuration>
        <fork>true</fork> <!-- 默認值爲false,必須設置爲true才能啓用熱部署功能(具體原因請見下文) -->
      </configuration>
    </plugin>
  </plugins>
</build>

靜態資源熱部署

對於HTML頁面、圖片、CSS樣式文件這些顯然不需要編譯的靜態資源,Spring Boot Devtools模塊通過內置的livereload服務端和瀏覽器的LiveReload插件共同實現熱部署。

  1. 服務端配置
spring:
  devtools:
    livereload:
      enabled: true # 啓用LiveReload服務端
      port: 35729 # LiveReload服務端口

默認僅觸發LiveReload事件的默認路徑如下: /META-INF/maven,/META-INF/resources,/resources,/static,/public/templates

  1. 瀏覽器配置
    無論時FireFox還是Chrome都有相應的LiveReload插件,按步驟安裝就可以了。

Java類資源熱部署

Spring Boot Devtools模塊是通過監聽Java類資源變化觸發應用熱部署,請注意這裏監聽的是Java類資源而不是Java源代碼文件,那麼什麼是Java類資源**呢?其實就是.class文件。
這樣從保存Java源代碼文件到Spring Boot Devtools監聽到Java類資源變化之間,就有一道不可逾越的鴻溝了。我們必須通過額外手段填平:

  1. 手動方式:修改Java源代碼文件後,執行mvn compile
  2. 自動方式:配置IDEA監聽Java源代碼文件變化,觸發重新編譯
    2.1. 右鍵點擊SpringBootApplication入口類文件,並點擊Create XXXX.main(),創建Application類型的Configuration;
    2.2. 勾選File/Settings/Compiler/Build Project automatically
    2.3. 按ctrl+shift+alt+/,然後選擇Registry並勾選Compiler autoMake allow when app running
    2.4. 通過IDEA左上角綠色的運行按鈕啓動Spring Boot應用,然後修改Java源代碼文件後IDEA會自動重新編譯項目,從而觸發Spring Boot Devtools熱部署。

更多配置配置項

spring:
  devtools:
  restart:
    enabled: true # 啓用熱部署
    exclude: main/static/** # 除默認路徑外,添加文件變化不觸發熱部署的路徑列表,多個路徑之間通過逗號分隔。
    additional: assets/** # 添加文件變化會觸發熱部署的路徑列表,多個路徑之間通過逗號分隔。
    additional-exclude: assets/public/** # 設置additional屬性指定的路徑下某些路徑的文件變化,不觸發熱部署,多個路徑之間通過逗號分隔。

默認不觸發熱部署的路徑有:/META-INF/maven,/META-INF/resources,/resources,/static,/public/templates

除了通過yml文件配置是否啓用熱部署功能外,還可以通過環境變量設置。在SpringBootApplication入口方法中加入

System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(MyApp.class, args);

疑難解答

  1. 在IDEA中修改文件後報 Maven Resource Compiler: Maven project configuration required for module 'lkm-api' isn't available. Compilation of Maven projects is supported only if build is started from an IDE.
    答:請使用IDEA那個綠色的運行按鈕啓動Spring Boot應用。
  2. 在IDEA中修改文件後沒有反應
    答:請稍等數秒自然會觸發重新編譯和熱部署的。

爲什麼是熱部署而不是熱替換呢?

開發過React或Vue的同學對熱替換應該不陌生吧,可以粗線條地理解爲將應用以比文件更細粒度的模塊或函數來組織,當源代碼發生變化時僅僅替換髮生變化的模塊或函數以及依賴它們的模塊或函數,通過最小化變更達到快速更新應用狀態。
而Spring Boot Devtools並沒有做成像React和Vue的開發工具那麼細粒度的更新,而是採取通過基類加載器重啓類加載器兩個類加載器來實現熱部署:

  1. 基類加載器,用於加載第三方依賴等開發階段不經常發生變化的Java類資源。
  2. 重啓類加載器,用於加載當前項目的Java類資源。若當前項目的Java類資源發生變化時,正在運行的重啓類加載器會被丟棄,並另外創建一個重啓類加載器並加載最新的Java類資源。

爲什麼pom.xml文件中的spring-boot-maven-plugin要設置爲獨立JVM進程運行呢(<fork>true</fork>)?

默認情況下<fork>false</fork>表示Maven採用運行自身的JVM虛擬機運行插件,而通過<fork>true</fork>則告知Maven啓動一個新的JVM虛擬機進程運行插件。
那麼爲什麼要耗費資源啓動新JVM虛擬機執行插件呢?直接運行不香嗎?

場景1——使用不同的JDK運行插件

執行mvn -v會顯示當前Maven運行的JDK版本信息,假設爲JDK1.8且編碼方式爲UTF-8。
由於Maven 3.8.1必須運行在JDK1.8以上,而項目只能在JDK1.6上編譯運行,因此需要通過如下方式執行插件:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <version>3.8.1</version>
  <configuration>
    <fork>true</fork>
    <!-- 指定JDK家目錄,默認爲環境變量PATH中的路徑 -->
    <executable>/path/to/jdk1.6</executable>
    <compilerVersion>1.3</compilerVersion>
  </configuration>
</plugin>

場景2——採用不同的JVM配置運行插件

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <version>3.8.1</version>
  <configuration>
      <fork>true</fork>
      <meminitial>128m</meminitial>
      <maxmem>1024m</maxmem>
      <compilerArgs>
        <arg>-XX:MaxPermSize=256m</arg>
      </compilerArgs>
  </configuration>
</plugin>

場景3——插件需要特定的JVM配置來運行

像spring-boot-maven-plugin那樣在啓用spring-boot-devtools模塊時需要特定JVM配置來運行,並且運行途中還會對重啓類加載器慘下殺手的,自然也要創建新的JVM虛擬機進程來運行纔可以了。

總結

Spring Boot不單單通過約定由於配置的原則簡化了過去Spring MVC那些繁瑣的配置文件,還提供各種顯著提升開發效率的自動化工具,而spring-boot-devtools就是其中一個。
倘若你所在的團隊還沒用上Spring Boot那麼是不是就無法享受這份便捷呢?我想JRebel IDEA插件應該是你需要的:)

轉載請註明來自:https://www.cnblogs.com/fsjohnhuang/p/14136491.html —— 肥仔John

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