網(wǎng)站的圖片水印怎么做百度資源提交
曾今Go語(yǔ)言里讓我最艷羨的兩個(gè)特性,一個(gè)是Goroutine,一個(gè)是native編譯。 Java 21的虛線程實(shí)現(xiàn)了類似Goroutine的能力。Spring Boot 3.x開始提供了GraalVM的支持,現(xiàn)在Spring Boot也能打包成native文件了。
這一篇文章的目標(biāo)是用一個(gè)案例講解如何將Spring Boot應(yīng)用打包成native文件。整個(gè)過程主要是4步:
- 環(huán)境準(zhǔn)備,講解怎么安裝GraalVM,安裝本地編譯器(gcc,cl)
- 測(cè)試工程,創(chuàng)建一個(gè)極簡(jiǎn)的Spring Boot應(yīng)用,只有個(gè)Controller
- 編譯打包,使用GraalVM、Maven將Spring Boot應(yīng)用構(gòu)建成可執(zhí)行文件
- 測(cè)試運(yùn)行,執(zhí)行生成的可執(zhí)行文件,訪問Controller看是否正常
1. 環(huán)境準(zhǔn)備
1. 前置條件
GraalVM依賴一些本地工具才能完成工作,這些工具包括:
- C的頭文件
- glibc-devel
- zlib
- gcc
- libstdc++-static
不同的操作系統(tǒng),采用的安裝方式不同,在Linux下可以使用包管理工具安裝,比如yum、apt等
Linux
yum install gcc glibc-devel zlib-devel
apt-get install build-essential libz-dev zlib1g-dev
Windows
Windows可以通過安裝Visual Studio完成依賴包安裝
- 安裝Visual Studio Build Tools
- 安裝Visual Studio
2. 安裝GraalVM
從官網(wǎng)選擇Java版本、平臺(tái)來(lái)下載,下載的zip包解壓即安裝,接下來(lái)只要設(shè)置環(huán)境變量JAVA_HOME、PATH即可
- 設(shè)置GRAALVM_HOME為解壓文件夾的根目錄
- 設(shè)置PATH為解壓文件夾下的bin
3. 驗(yàn)證安裝
通過執(zhí)行native-image --help,確認(rèn)我們安裝成功
4. 參考資料
關(guān)于GraalVM的安裝過程,可以參考官方的Get Started文檔: Getting Started with GraalVM
2. 測(cè)試工程
1. 創(chuàng)建工程
使用mvn archetype:generate根據(jù)archetype maven-archetype-quickstart生成一個(gè)最簡(jiǎn)單的Java項(xiàng)目。
mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DgroupId=com.keyniu.dis -DartifactId=DiveInSpring -Dversion=0.1 -Dpackage=com.keyniu.dis -DinteractiveMode=false
2. 添加Spring Boot支持
修改pom.xml選擇spring-boot-starter-parent作為parent,添加native-maven-plugin插件
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.keyniu.dis</groupId><artifactId>DiveInSpring</artifactId><version>0.1</version><name>DiveInSpring</name><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.3.0</version></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.graalvm.buildtools</groupId><artifactId>native-maven-plugin</artifactId></plugin></plugins></build></project>
3. 添加測(cè)試類
寫一個(gè)最簡(jiǎn)單啟動(dòng)引導(dǎo)類,提供一個(gè)最簡(jiǎn)單的接口/hello,用于后續(xù)測(cè)試。
package com.keyniu.dis;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@SpringBootApplication
@RestController
public class DiveInMain {@GetMapping("/hello")public String hello(@RequestParam("name") String name) {return "hello," + name;}public static void main(String[] args) {SpringApplication.run(DiveInMain.class);}
}
3. 編譯打包
1. 命令行窗口
為了讓GraalVM能引用到VisualStudio的編譯工具,我選擇在x64 Native Tools窗口中運(yùn)行接下來(lái)的命令。
在執(zhí)行命令之前,確保你的環(huán)境變量設(shè)置正確,有添加GraalVM相關(guān)的配置
set GRAALVM_HOME=D:\Programs\GraalVM
set PATH=D:\Programs\GraalVM\bin;%PATH%
2. 進(jìn)行native編譯
在工程的根目錄下執(zhí)行mvn -Pnative native:compile,進(jìn)行編譯,最后會(huì)生成一個(gè)exe到工程的target目錄下,輸入如下
D:\Workspace\DiveInSpring>mvn -Pnative native:compile
...
Produced artifacts:D:\Workspace\DiveInSpring\target\DiveInSpring.exe (executable)
4. 測(cè)試運(yùn)行
只需要在命令行里輸入DiveInSpring.exe執(zhí)行,可以看到只需要0.063s就能完成啟動(dòng),這個(gè)項(xiàng)目如果通過java -jar啟動(dòng)的話大概耗時(shí)0.97s,還是快了很多的。打包后的exe文件大小是80M。
通過curl命令驗(yàn)證,接口正常提供服務(wù)
5. 使用建議
可以看到整個(gè)構(gòu)建過程已經(jīng)相當(dāng)?shù)捻槙?#xff0c;從可執(zhí)行文件的大小,啟動(dòng)時(shí)間,內(nèi)存占用都于明顯的提升,應(yīng)該說Spring + GraalVM離成熟應(yīng)用已經(jīng)不遠(yuǎn)了。由于GraalVM使用了Closed World Optimization,實(shí)際上這個(gè)可執(zhí)行程序還是有一些限制的,主要是:
- Class初始化,有些初始化會(huì)在build期間完成,可以參考GraalVM文檔: Class Initialization in Native Image
- 反射和動(dòng)態(tài)代理,需要的編譯期間完成
- 不支持JNI,如果有本地方法調(diào)用需要根據(jù)GraalVM提供的接口定制實(shí)現(xiàn)
- 執(zhí)行時(shí)無(wú)法訪問字節(jié)碼,正常的debug、監(jiān)控等用JVM TI實(shí)現(xiàn)的功能都不再可用
在SpringBoot中, 像profiles、 條件配置、 @Enable*等功能會(huì)受到影響,而其實(shí)這些特性正在被廣泛使用,這些限制在完全解決之前實(shí)際使用還是有障礙的。關(guān)于可以執(zhí)行文件的DEBUG、監(jiān)控在GraalVM官網(wǎng)都已經(jīng)有對(duì)應(yīng)的文檔,但是將它和公司內(nèi)部的監(jiān)控報(bào)警做集成還有一段路要走,已經(jīng)看到黎明的曙光了。
A. 參考資料
- GraalVM構(gòu)建Swing應(yīng)用
- 使用GDB Debug由GraalVM構(gòu)建的程序,Debug Native Executables with GDB
- 讓可執(zhí)行文件支持JFR,Build and Run Native Executables with JFR
- 手動(dòng)創(chuàng)建Spring Boot工程