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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM