SpringBoot3.x原生鏡像-Native Image嘗鮮
- 2022 年 10 月 30 日
- 筆記
- JAVA, springboot
前提
Spring
團隊致力於為Spring
應用程式提供原生映像支援已經有一段時間了。在SpringBoo2.x
的Spring Native
實驗項目中醞釀了3年多之後,隨著Spring Framework 6
和Spring Boot 3
的發布,對應的項目就是Spring Native
,原生鏡像支援將會發布GA
版本(換言之就是,Native Image
相關支援會在Spring Boot 3
的GA
版本中一起發布)。
前面這一段簡介摘抄自參考資料中的《Native Support in Spring Boot 3.0.0-M5》
筆者在寫這篇文章(2022-10-28
)前後SpringBoot
尚未發布3.x GA
,版本3.0.0-M5+
算是GA
前相對穩定的版本,這裡選用當前3.x
的最新非GA
版本3.0.0-RC1
進行調研。
什麼是Native Image
Native Image
,這裡直譯為原生鏡像或者本地鏡像,是一種提前將(Java
)程式碼編譯為二進位文件(原生可執行文件,native executable
)的技術。原生可執行文件只包含運行時所需要的程式碼,即應用程式類、標準庫類、語言運行時和來自JDK
的靜態鏈接的原生程式碼(也就是這樣的二進位文件可以直接運行,不需要額外安裝JDK
)。由原生鏡像生成的可執行文件有幾個重要的優點:
- 使用
Java
虛擬機所需資源的一小部分,因此運行成本更低 - 啟動時間大幅度下降,以毫秒為單位
- 不需要進行預熱即可提供最佳性能
- 可以打包到輕量級容器映像中以便快速有效地部署
- 減少了攻擊面(這個和網路安全相關)
Spring Boot 3
中使用GraalVM
方案提供Native Image
支援。
安裝GraalVM
在//www.graalvm.org/downloads – Download GraalVM頁面中下載對應作業系統的GraalVM
:
筆者開發環境使用的作業系統是Windows10
,下載和選用下圖中的安裝包:
解壓完成後配置一下JAVA_HOME
、GRAALVM_HOME
並且把GRAALVM_HOME\bin
添加到PATH
中。完成後可以執行一下java -version
進行驗證:
如果已經安裝了其他版本的JDK,先暫時全局替換為GraalVM,也就是JAVA_HOME、GRAALVM_HOME同時配置為GraalVM的解壓目錄,因為目前看來這樣做才能正常打包原生鏡像
確定GraalVM
版本無誤,到此安裝完成。另外,需要配置好了Maven
,建議重新安裝一個3.6.x+
版本的Maven
並且把MAVEN_HOME\bin
添加到PATH
中。
編寫應用程式
新建一個命名為spring-boot-native-image
的Maven
項目或者模組,選用剛才下載好的GraalVM
:
項目的POM
文件引入下面幾組依賴:
spring
的快照repository
,因為需要下載RC1
版本依賴,暫時不能從中央倉庫拉取spring-boot-starter-parent
,定義版本為RC1
native-maven-plugin
插件,用於原生鏡像打包spring-boot-starter-web
,用於構建一個簡單的web
項目
<!-- spring-boot-starter-parent -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.0-RC1</version>
</parent>
<!-- repository -->
<repositories>
<repository>
<id>spring-snapshots</id>
<url>//repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<url>//repo.spring.io/milestone</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<url>//repo.spring.io/snapshot</url>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<url>//repo.spring.io/milestone</url>
</pluginRepository>
</pluginRepositories>
<!-- spring-boot-starter-web -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<!-- native-maven-plugin -->
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>0.9.16</version>
<extensions>true</extensions>
<executions>
<execution>
<id>build-native</id>
<goals>
<goal>compile-no-fork</goal>
</goals>
<phase>package</phase>
</execution>
<execution>
<id>test-native</id>
<goals>
<goal>test</goal>
</goals>
<phase>test</phase>
</execution>
</executions>
<configuration>
<mainClass>cn.vlts.NativeApplication</mainClass>
<imageName>native-app</imageName>
<buildArgs>
<buildArg>--verbose</buildArg>
</buildArgs>
</configuration>
</plugin>
</plugins>
最終的POM
文件看起來如下:
項目中只有一個啟動類cn.vlts.NativeApplication
,編寫了main
方法和一個用於集成測試的控制器方法:
@RestController
@SpringBootApplication
public class NativeApplication {
public static void main(String[] args) {
SpringApplication.run(NativeApplication.class, args);
}
@GetMapping(path = "/hello")
public ResponseEntity<String> hello() {
return ResponseEntity.ok("world");
}
}
打包和調試
完成項目配置和程式碼編寫後,執行下面的Maven
命令進行打包:
mvn package -Pnative
打包過程可能會遇到下面的問題:
- 最有可能的問題:
Default native-compiler executable 'cl.exe' not found via environment variable PATH
解決方案在Stackoverflow
對應的問題回答中找到:
其實就是在Window
作業系統開發環境下基於GraalVM
構建原生鏡像依賴Microsoft Visual C++ (MSVC)
,建議安裝MSVC 2017 15.5.5+
,可以安裝Visual Studio (2019)
並且安裝對應的MSVC
。
因為很早之前筆者在調試Rust
時候已經安裝過Visual Studio 2019
用於其debug
工具鏈,這裡無須進行安裝。在安裝Visual Studio
勾選MSVC vXXX
的組件進行安裝即可,然後需要把對應的MSVC
工具的bin
目錄添加到PATH
中(這個目錄一般是VS_HOME\VC\Tools\MSVC\版本號\bin\Hostx64\x64
):
- 其次可能遇到的問題:打包過程出現
stdio.h
庫文件報錯或者找不到主類Main entry point class 'app.jar' not found x.y.Application
其實還是因為MSVC
的問題,在GraalVM
文檔中有提示如下:
簡單來說就是必須在Visual Studio
自帶的命令行工具x64 Native Tools Command Prompt
中執行native image
相關命令,這個命令行工具初始化如下:
在x64 Native Tools Command Prompt
中先進入目標項目根目錄,然後執行mvn -Pnative package
:
最終看到BUILD SUCCESS
字眼,項目的target
目錄下可以看到一個.exe
和一個.jar
文件,而.exe
文件就是前面一直提到的可執行的二進位文件:
直接運行它:
可以看到這個文件運行完全不依賴外部Java
虛擬機,並且啟動速度極快(600
毫秒左右),可以用POSTMAN
等工具測試程式介面:
到此可以驗證程式功能正常。
小結
SpringBoot3.x
原生鏡像正式發布後會是SpringBoot
在雲原生領域的一個巨大進步,讓我們拭目以待。但是就目前來看,常用的Windows
開發環境下想要嘗試native image
技術需要解決比較多的問題,Linux
和Unix
平台下尚未驗證,希望後面的版本迭代能夠降低使用難度並且支援一個命令多平台打包的功能。
參考資料:
(本文完 c-2-d e-a-20221030)