使用Spring Boot DevTools優化你的開發體驗

東溪陳姓少年發表於2020-08-24

場景再現

某日少年收到前端同學發來的訊息說聯調的介面響應異常?,少年表現的很平靜?,因為這種事情太平常了?。於是詢問詳情之後開始開啟自己的程式碼查詢問題所在,沒過五分鐘就發現了問題。少年修改完程式碼之後將本地啟動的專案停止然後再重新啟動。由於當前的服務端專案是一個巨大的單體應用,啟動需要花三四分鐘時間,於是少年就拿出手機開始刷起朋友圈。刷著刷著(由於注意力分散不知不覺花了十幾分鍾)突然意識到專案已經重新啟動,於是通知前端同學檢視效果。

分析問題

上面的場景可能對很多開發者來說感同身受,在開發中修改專案是很平常且頻繁的一件事情。當我們修改完程式碼或其他檔案的時候,我們會重新啟動專案來驗證修改是否真的生效(這裡忽略我們編寫的測試程式碼),以供前端或者其他客戶端來使用我們的修改。但是不知不覺這樣的流程浪費了我們很多時間,甚至被迫分散我們的注意力(開啟社交軟體、看新聞、和同事聊天),這些問題對我們的生產力是一個極大的威脅。

spring-boot-devtools

能否有一種方案可以讓我們對專案的修改快速生效,從而節省那些我們本該可以利用的時間呢?幸好有一種工具可以解決當前所存在的問題,這就是**Spring Boot Dev Tools**

原理簡介

您可能會說,瞭解Spring Boot Dev Tools的工作原理並不重要,但是由於開發過程中存在很多複雜的情況,所以瞭解Spring Boot Dev Tools的工作原理是對我們有幫助的。

Spring Boot Dev Tools鉤接(hooks into)到Spring Boot的類載入器中,以提供一種方法來按需重新啟動應用程式上下文或重新載入已更改的靜態檔案而無需重新啟動整個應用程式。

為此,Spring Boot Dev Tools將劃分應用程式的類路徑並分配給兩個不同的類載入器:

  • 基本類載入器(base classloader):包含一些不可變類或者幾乎不會被修改檔案,例如Spring Boot JAR或第三方庫。
  • 重新啟動類載入器(restart classloader):包含應用程式的檔案,這些檔案在專案開發過程中將頻繁更改。

重新啟動應用程式後,現有的重新啟動類載入器將被丟棄,新的重新啟動類載入器將被啟動。這種方法意味著應用程式的重啟通常比“冷啟動”要快得多,因為基本類載入器沒有受到影響並且一直存在著。

引入依賴

當我們使用intellij IDEASpring Initializr建立專案時,Spring Initializr提供了內建的Spring Boot Dev Tools依賴選項,我們只需選擇它即可。

imgSpring Initializr中引入Spring Boot Dev Tools

Maven專案中引入Spring Boot Dev Tools

在專案的pom.xml檔案中引入Spring Boot Dev Tools依賴即可

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>

專案演示

單模組

在專案中新增一個簡單的Controller

@SpringBootApplication
public class DevToolApplication {

    public static void main(String[] args) {
        SpringApplication.run(DevToolApplication.class, args);
    }

    @RestController
    public static class HelloWorld {
        @GetMapping("test")
        public ResponseEntity<?> getTest() {
            return ResponseEntity.ok("hello world");
        }
    }
}

啟動專案,訪問http://localhost:8080/test,返回如下:

img

我們簡單修改程式碼

@RestController
public static class HelloWorld {
    @GetMapping("test")
    public ResponseEntity<?> getTest() {
        return ResponseEntity.ok("hello world after change file");
    }
}

執行命令mvn compile,執行完畢重新訪問http://localhost:8080/test

img

可以看到,我們的更改已經生效了。

多模組

假設現在我們的專案引用了其他專案作為子模組

<dependency>
    <groupId>org.example</groupId>
    <artifactId>untitled</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

我們需要在程式執行時,對上述子模組的修改也即時生效。

在多模組專案中使用Spring Boot Dev Tools比單模組專案略複雜,由於在多模組專案中主模組對子模組是引用關係,並且在執行時主模組通過引用子模組的jar檔案的形式來啟動應用程式,根據前面Spring Boot Dev Tools的原理,jar檔案的載入將歸屬於基本類載入器,因此按照現在的做法無法做到子模組的修改即時生效。

不過Spring Boot Dev Tools提供了對多模組專案的支援,我們只需要新增簡單的配置即可實現多模組專案的修改即時生效。

在專案的/resources中建立META-INF/spring-devtools.properties檔案,並新增配置

restart.include.projectcommon=/untitled-1.0-SNAPSHOT.jar

上述配置表明重新啟動類載入器在重新啟動的時候,會載入最新的子模組依賴,從而做到子模組的修改即時生效。

現在子模組中存在如下類

public class DemoA {
    private String name;

    public String getName() {
        return name;
    }

    public DemoA setName(String name) {
        this.name = name+"cgsj111";
        return this;
    }
}

主模組中引用了上面的類

@RestController
public static class HelloWorld {
    @GetMapping("test")
    public ResponseEntity<?> getTest() {
        DemoA demo = new DemoA();
        demo.setName("demo name");
        return ResponseEntity.ok(demo);
    }
}

此時啟動應用程式,訪問http://localhost:8080/test

img

可以看到響應正常返回,此時我們修改子模組的程式碼

public class DemoA {
    private String name;

    public String getName() {
        return name;
    }

    public DemoA setName(String name) {
        this.name = name+"cgsj111 After Change";
        return this;
    }
}

然後在主模組中執行命令 mvn compile,此時再次訪問介面

img

可以看到子模組的修改已經在主模組中即時生效了。

遠端除錯

Spring Boot Dev Tools所展現的高效便捷之處不僅僅侷限於本地除錯,對於遠端除錯也有很好的支援。選擇性地啟用遠端支援是因為啟用它可能會帶來安全風險。僅當在受信任的網路上執行或使用SSL保護時,才應啟用它。如果這兩個選項都不滿足,則不應使用DevTools的遠端支援。您永遠不應該在生產環境中啟用他。

啟用它需要確保構建物中包含devtools,修改至如下配置:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <!--確保專案打包是將Devtools包含進去-->
                <excludeDevtools>false</excludeDevtools>
            </configuration>
        </plugin>
    </plugins>
</build>

然後,您需要設定spring.devtools.remote.secret屬性。像任何重要的密碼或機密一樣,該值應唯一且強壯,以免被猜測或強行使用,例如,在application.properties中設定:

spring.devtools.remote.secret=cgsj8377

遠端devtools支援分為兩部分:接受連線的伺服器端端點和在IDE中執行的客戶端應用程式。設定spring.devtools.remote.secret屬性後,將自動啟用伺服器元件,客戶端元件必須手動啟動。

除錯演示

在專案資料夾中執行命令 mvn package生成jar檔案,將jar檔案部署到伺服器(在這裡我們以本地執行jar包的方式來模擬遠端部署)。然後在IDE進行如下配置(以Intellij IDEA為例)

img

如上圖我們新增了一個啟動器,啟動類為org.springframework.boot.devtools.RemoteSpringApplication,並且傳遞了一個程式引數來指定遠端應用程式的地址,此處筆者在本機上試驗所以是一個本機的地址。

接下來我們啟動我們剛剛建立的啟動器img

啟動日誌如下

img

修改程式碼至如下

@RestController
public static class HelloWorld {
    @GetMapping("test")
    public ResponseEntity<?> getTest() {
        DemoA demo = new DemoA();
        demo.setName("remote test");
        return ResponseEntity.ok(demo);
    }
}

然後執行命令mvn compile,可以看到我們的更改在執行的程式中即時生效了

img

總結

在我們的日常的開發過程中總會存在各種各樣的“等待”,這些時刻很大程度上會影響開發者的效率和注意力。而Developer Tools的出現緩解了這個問題,他使應用程式的除錯更加的便捷高效。有一點要注意的是在讓我們的更改生效之前需要執行mvn compile命令,從而使原生程式碼能被編譯成程式可以理解的位元組碼檔案。

本文示例程式碼:https://gitee.com/jeker8chen/dev-tool


本文參考資料:

https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-devtools

https://reflectoring.io/spring-boot-dev-tools/


??????????????????

歡迎訪問筆者部落格:blog.dongxishaonian.tech

相關文章