Spring Native 中文文件
https://docs.spring.io/spring-native/docs/current/reference/htmlsingle/#getting-started-buildpacks
1.概述
Spring Native 為使用 GraalVM 原生映象編譯器編譯 Spring 應用為本地可執行檔案提供支援。
與 Java 虛擬機器相比,原生映象可以在許多場景下降低工作負載,包括微服務,函式式服務,非常適合容器和 Kubernetes。
使用原生映象有明顯優勢,如快速啟動,提高峰值效能以及降低記憶體消耗。
GraalVM 專案也有一些缺點和權衡,希望隨著時間的推移有所改進。構建本地映像是一個繁重的過程,比常規應用程式要慢,預熱後的執行時優化也更少。最後,比起 JVM 很多場景下還不成熟。
常規 JVM 和此本機映像平臺之間的主要區別:
- 在構建時會從主入口點對應用程式進行靜態分析。
- 在構建時將未使用的零件刪除。
- 反射,資源和動態代理需要配置。
- 類路徑在構建時是固定的。
- 沒有類延遲載入:可執行檔案中附帶的所有內容都將在啟動時載入到記憶體中。
- 一些程式碼將在構建時執行。
- 一些 Java 切面類的特性未得到完全支援。詳情
此專案的目標是孵化對 Spring Native
(Spring JVM的替代方案)的支援,並提供旨在打包到輕量級容器中的本地部署選項, 目標是在此新平臺上直接支援 Spring 應用而不需要修改程式碼。
更多的工作正在進行中,瞭解更多詳情可以檢視支援列表
1.1 組成模組
Spring Native 由以下模組組成:
spring-native
:執行Spring Native所需的執行時依賴,還提供了Native hints API。spring-native-configuration
:Spring AOT 外掛使用的 Spring 類的配置提示,包括各種 Spring Boot 自動配置。spring-native-docs
:參考指南,採用 asciidoc 格式。spring-native-tools
:用於檢視映象構建配置和輸出的工具。spring-aot
:Maven 和 Gradle 外掛公共的 AOT 轉換基礎架構。spring-aot-gradle-plugin
spring-aot-maven-plugin
:AOT 轉換的 Maven 外掛。samples
:包含各種演示功能用法的示例,也用於整合測試。
2. 上手
主要有兩種的方式來構建 Spring Boot 原生應用:
使用 Spring Boot Buildpacks Support
生成一個包含本地可執行檔案的輕量級容器。
使用 GraalVM native image Maven plugin support
來生成本地可執行檔案。
2.1 通過 Buildpacks
上手
這部分提供了使用 Cloud Native Buildpacks 構建Spring Boot本機應用程式的實用概述。
建立新的 SpringBootNative 專案的最簡單方法是轉到 start.spring.io,新增 "Spring Native" 依賴項並生成專案。
2.1.1 系統要求
需要安裝 Docker,Get Docker
如果使用的是 Linux,需要配置為允許非 root 使用者。點選檢視如何設定
在 MacOS上,建議將分配給 Docker 的記憶體至少增加到
8GB
,並且多分配點
CPU,原因參見此 Stackoverflow 解答。在 Microsoft Windows上請確保啟用 Docker WSL 2 後端以獲得更好的效能。
2.1.2 獲取示例專案
git clone https://github.com/spring-guides/gs-rest-service
cd gs-rest-service/complete
驗證Spring Boot版本
Spring Native 0.9.2 僅支援 Spring Boot 2.4.5,建議使用指定版本。
Maven
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
<relativePath/>
</parent>
Gradle Groovy
plugins {
// ...
id 'org.springframework.boot' version '2.4.5'
}
Gradle Kotlin
plugins {
// ...
id("org.springframework.boot") version "2.4.5"
}
新增 Spring Native 依賴org.springframework.experimental:spring-native
提供像 @NativeHint
這樣的本機配置 API,以及其他作為原生映像執行 Spring 應用所需的必需類。使用 Maven 時需要顯式的特別配置。
Maven
<dependencies>
<!-- ... -->
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-native</artifactId>
<version>0.9.2</version>
</dependency>
</dependencies>
Gradle Groovy
// No need to add the spring-native dependency explicitly with Gradle, the Spring AOT plugin will add it automatically.
Gradle Kotlin
// No need to add the spring-native dependency explicitly with Gradle, the Spring AOT plugin will add it automatically.
新增 Spring AOT 外掛
Maven
<build>
<plugins>
<!-- ... -->
<plugin>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-aot-maven-plugin</artifactId>
<version>0.9.2</version>
<executions>
<execution>
<id>test-generate</id>
<goals>
<goal>test-generate</goal>
</goals>
</execution>
<execution>
<id>generate</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Gradle Groovy
plugins {
// ...
id 'org.springframework.experimental.aot' version '0.9.2'
}
Gradle Kotlin
plugins {
// ...
id("org.springframework.experimental.aot") version "0.9.2"
}
該外掛提供了許多用於自定義轉換的選項,有關更多詳細資訊參見Configuring Spring AOT。
啟用原生映象支援
Spring Boot 的 Cloud Native Buildpacks support
使您可以直接為 Spring Boot 應用構建容器。該 buildpack 通過BP_NATIVE_IMAGE
環境變數啟用,如下所示:
Maven
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<builder>paketobuildpacks/builder:tiny</builder>
<env>
<BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
</env>
</image>
</configuration>
</plugin>
Gradle Groovy
bootBuildImage {
builder = "paketobuildpacks/builder:tiny"
environment = [
"BP_NATIVE_IMAGE" : "true"
]
}
Gradle Kotlin
tasks.getByName<BootBuildImage>("bootBuildImage") {
builder = "paketobuildpacks/builder:tiny"
environment = mapOf(
"BP_NATIVE_IMAGE" to "true"
)
}
tiny
builder 允許使用較小的空間並減少出錯,為了改善開發人員的使用體驗,也可以使用base
(預設) 或full
builders 在映像中提供的更多工具。
可選的
native-image
引數可以使用BP_NATIVE_IMAGE_BUILD_ARGUMENTS
環境變數新增 。
Maven倉庫
構建 spring-native
依賴所必需的庫:
Maven
<repositories>
<!-- ... -->
<repository>
<id>spring-release</id>
<name>Spring release</name>
<url>https://repo.spring.io/release</url>
</repository>
</repositories>
Gradle Groovy
repositories {
// ...
maven { url 'https://repo.spring.io/release' }
}
Gradle Kotlin
repositories {
// ...
maven { url = uri("https://repo.spring.io/release") }
}
Spring AOT 的外掛也是需要配置的:
Maven
<pluginRepositories>
<!-- ... -->
<pluginRepository>
<id>spring-release</id>
<name>Spring release</name>
<url>https://repo.spring.io/release</url>
</pluginRepository>
</pluginRepositories>
Gradle Groovy
pluginManagement {
repositories {
// ...
maven { url 'https://repo.spring.io/release' }
}
}
Gradle Kotlin
pluginManagement {
repositories {
// ...
maven { url = uri("https://repo.spring.io/release") }
}
}
2.1.3 構建原生應用
可以按以下命令構建本地應用程式:
- Maven
$ mvn spring-boot:build-image
- Gradle Groovy
$ gradle bootBuildImage
- Gradle Kotlin
$ gradle bootBuildImage
在編譯期間,可能看到很多
WARNING: Could not register reflection metadata
訊息,不必擔心,以後的版本中會逐漸消失,詳細資訊見#502。
上面命令的執行結果會建立一個 Linux 容器,使用 GraalVM 本地映象編譯器構建原生映象。
2.1.4 執行原生應用
最簡單的可以使用 docker:
$ docker run --rm -p 8080:8080 rest-service:0.0.1-SNAPSHOT
docker-compose 也可以:
version: '3.1'
services:
rest-service:
image: rest-service:0.0.1-SNAPSHOT
ports:
- "8080:8080"
啟動時間應該小於100ms, 與之相比在JVM上啟動可能需要1500ms。
服務啟動後訪問 http://localhost:8080/greeting
{"id":1,"content":"Hello, World!"}
2.2 通過原生映象的 Maven 外掛上手
本節為您提供了使用 native image Maven plugin
構建 Spring Boot 原生應用的實用介紹。這是 RESTful Web Service getting started guide
的一部分。
目前還沒有一個官方的本地映象 Gradle 外掛,所以本部分僅涉及 Maven。如果您對不使用 using Buildpacks
來構建 Gradle 原生映像感興趣,可以投票並訂閱 graal/issue3302。
2.2.1 系統要求
在安裝 GraalVM native-image
編譯器之前,需要一些準備工作 prerequisites
, 然後需要本機安裝一個原生映象編譯器。
在 MacOS 或 Linux 推薦使用 SDKMAN:
- Install SDKMAN
- 安裝 GraalVM :
sdk install java 21.0.0.2.r8-grl
for Java 8 orsdk install java 21.0.0.2.r11-grl
for Java 11 - 使用最新的 JDK :
sdk use java 21.0.0.2.r8-grl
或sdk use java 21.0.0.2.r11-grl
。 - 執行
gu install native-image
把native-image extensions
引入 JDK。
如果您使用的是 Microsoft Windows,則可以按以下步驟手動安裝 GraalVM 構建:
- 下載 GraalVM 21.0.0.2。
- 設定適當的
JAVA_HOME
和PATH
。 - 執行
gu install native-image
把native-image extensions
引入 JDK。
2.2.2 示例專案安裝
可以使用以下命令來檢索完整的“ RESTful Web服務”指南:
git clone https://github.com/spring-guides/gs-rest-service
cd gs-rest-service/complete
新增Spring Native依賴項
<dependencies>
<!-- ... -->
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-native</artifactId>
<version>0.9.2</version>
</dependency>
</dependencies>
新增 Spring AOT 外掛
<build>
<plugins>
<!-- ... -->
<plugin>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-aot-maven-plugin</artifactId>
<version>0.9.2</version>
<executions>
<execution>
<id>test-generate</id>
<goals>
<goal>test-generate</goal>
</goals>
</execution>
<execution>
<id>generate</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
該外掛提供了許多用於自定義轉換的選項,有關更多詳細資訊,請參見 Configuring Spring AOT。
啟用本地編譯支援
GraalVM 提供了一個Maven 外掛來從您的 Maven 構建中呼叫本地編譯器。以下示例添加了一個 native-image
在 package
階段中觸發外掛:
<profiles>
<profile>
<id>native-image</id>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.nativeimage</groupId>
<artifactId>native-image-maven-plugin</artifactId>
<version>21.0.0.2</version>
<configuration>
<!-- The native image build needs to know the entry point to your application -->
<mainClass>com.example.restservice.RestServiceApplication</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>native-image</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
在預設的Spring Boot設定中,它們spring-boot-maven-plugin還將在此 package 階段執行,並用重新打包的可執行 jar 替換常規 jar。為了避免兩個外掛之間發生衝突,請確保 exec為可執行jar指定一個如下所示的分類器:
<plugins>
<!-- ... -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
</plugins>
Maven倉庫
將構建配置為包括spring-native依賴項所需的儲存庫,如下所示:
<repositories>
<!-- ... -->
<repository>
<id>spring-release</id>
<name>Spring release</name>
<url>https://repo.spring.io/release</url>
</repository>
</repositories>
Spring AOT外掛還需要專用的外掛儲存庫:
<pluginRepositories>
<!-- ... -->
<pluginRepository>
<id>spring-release</id>
<name>Spring release</name>
<url>https://repo.spring.io/release</url>
</pluginRepository>
</pluginRepositories>
2.2.3 構建原生應用
$ mvn -Pnative-image package
在 Windows上,請確保按照 GraalVM native-image prerequisites
中的建議使用 x64 版本的工具包。
上面的命令會建立一個本地可執行檔案,該可執行檔案在 target
目錄中。
2.2.4 執行原生應用程式
$ target/com.example.restservice.restserviceapplication
現在該服務已啟動,訪問 localhost:8080/greeting
應該能看到:
{"id":1,"content":"Hello, World!"}
3. 支援
本節定義了已經針對 Spring Native 0.9.2
進行了驗證的 GraalVM 版本,語言和依賴關係,該版本在本部分中定義的範圍內提供了 beta支援。如果專案使用的是受支援的依賴項,則可以在專案上進行嘗試;如果出現問題,raise bugs
或 contribute pull requests。
Beta支援也意味著將來可能有破壞性變更,但是會提供遷移方法和文件。
3.1 GraalVM
支援 GraalVM 21.0.0.2
版本,請參閱相關發行說明 release notes。影響 Spring 生態的 GraalVM issues 在 the spring
label 。
3.2 語言
支援 Java 8,Java 11 和 Kotlin 1.3+。
Java 11 原生映象可能編譯出偏大的映象檔案,原因詳見 oracle/graal#3163。
請注意 一個 Kotlin 的 bug: that Kotlin bug, 在 Kotlin 1.5+中已被修復。
支援Kotlin協程,但協程在生成一個 Object
返回型別的位元組碼時需要額外的反射項。
3.3 特性標誌
某些功能(例如HTTPS)可能需要一些其他標誌,請檢視 Native image options 獲取更多詳細資訊。當識別出一些特定使用場景時,Spring Native 會嘗試自動設定所需的標誌。
3.4. Spring Boot
Spring Native 0.9.2
設計用於Spring Boot 2.4.5
。為了保證支援和相容性,最新的Spring Boot 2.x
次要版本的每個修補版本都會發佈一個新版本的Spring Native
。
支援以下 starter
,除非另有說明,否則 group ID 預設org.springframework.boot
。
-
spring-boot-starter-actuator
:支援 WebMvc 和 WebFlux,以及 metrics 和 tracing infrastructure。請注意actuators
會顯著增加佔用空間,將來的版本中會對其進行優化。 -
spring-boot-starter-data-elasticsearch
-
spring-boot-starter-data-jdbc
-
spring-boot-starter-data-jpa
-
[Hibernate build-time bytecode enhancement]
(https://docs.jboss.org/hibernate/orm/5.4/topical/html_single/bytecode/BytecodeEnhancement.html#_build_time_enhancement) 需要手動配置 -
hibernate.bytecode.provider=none
會被自動設定 -
spring-boot-starter-data-mongodb
-
spring-boot-starter-data-neo4j
-
spring-boot-starter-data-r2dbc
-
spring-boot-starter-data-redis
-
spring-boot-starter-jdbc
-
spring-boot-starter-logging
-
spring-boot-starter-mail
-
spring-boot-starter-thymeleaf
-
spring-boot-starter-rsocket
-
spring-boot-starter-validation
-
spring-boot-starter-security
:支援WebMvc和WebFlux表單登入,HTTP基本身份驗證和OAuth 2.0。還支援 RSocket security。 -
spring-boot-starter-oauth2-resource-server
:支援WebMvc和WebFlux。 -
spring-boot-starter-oauth2-client
:支援WebMvc和WebFlux。 -
spring-boot-starter-webflux
:- 對於Web支援,目前僅支援 Reactor Netty。
- 對於WebSocket支援,支援 Tomcat,Jetty 9,Undertow 和 Reactor Netty。不支援 Jetty 10。
-
spring-boot-starter-web
:- 目前僅支援Tomcat。
--enable-https
標記是 HTTPS 支援所必需的。org.apache.tomcat.experimental:tomcat-embed-programmatic
可以使用依賴性代替tomcat-embed-core
和依賴tomcat-embed-websocket
,以優化佔用空間。
-
spring-boot-starter-websocket
-
com.wavefront:wavefront-spring-boot-starter
: 支援Quartz Job Scheduling 引擎。它添加了 Quartz 所需的型別,並自動註冊任意 Job 子類以進行反射。
! 目前尚不支援Devtools,您可以按照 #532 進行了解。
3.5 Spring Cloud
! Spring Native 0.9.2 設計為與 Spring Cloud 2020.0.2 一起使用。
Group ID 為 org.springframework.cloud
。
使用Spring Native時,出於相容性和佔用空間的考慮,
spring.cloud.refresh.enabled
將設定false
,spring.sleuth.async.enabled
也會設定為false
, 因為此功能會導致建立過多的代理浪費空間。
spring-cloud-starter-bootstrap
spring-cloud-starter-config
spring-cloud-config-client
spring-cloud-config-server
spring-cloud-starter-netflix-eureka-client
(僅適用於Java 11)spring-cloud-starter-task
spring-cloud-function-web
--enable-https
標記是 HTTPS 支援所必需的。
spring-cloud-function-adapter-aws
spring-cloud-starter-function-webflux
--enable-https
標記是 HTTPS 支援所必需的。spring-cloud-starter-sleuth
3.6 其他
- Lombok
- Spring Kafka
- GRPC
- H2 database
- Mysql JDBC driver
- PostgreSQL JDBC driver
3.7 侷限性
不支援類的 CGLIB 代理,目前僅支援介面上的 JDK 動態代理。因此使用Spring Native 時需要將 spring.aop.proxy-target-class
設定為 false
。
如果使用
@Configuration
未設定proxyBeanMethods=false
並且僅使用方法引數來注入 Bean 依賴項, Spring Native 會自動處理該情況,不需要CGLIB代理。
4. Spring AOT
Spring AOT構建外掛旨在通過利用應用程式的上下文(類路徑,配置)來生成和編譯原始碼,從而改善本機影象的相容性和佔用空間。在執行您的應用程式和測試之前將呼叫它,並且可能潛在地需要其他IDE配置。
4.1 Maven
外掛宣告如下:
Maven
<build>
<plugins>
<!-- ... -->
<plugin>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-aot-maven-plugin</artifactId>
<version>0.9.2</version>
<executions>
<execution>
<id>test-generate</id>
<goals>
<goal>test-generate</goal>
</goals>
</execution>
<execution>
<id>generate</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
當使用 mvn verify
或 mvn package
時,會在 Maven 生命週期中自動呼叫 spring-aot:generate
(process-test-classes
階段)和 spring-aot:test-generate
(prepare-package
階段)。spring-aot:*
的目標並不意味需要手動觸發,它們依賴於生命週期的其他階段。原始碼生成的目錄是 target/generated-sources/spring-aot/
, 測試原始碼在 target/generated-test-sources/spring-aot/
目錄。
由於 AOT 外掛的臨時限制,如果開發人員希望使用 Spring Boot Maven 外掛執行應用需要手動觸發
package
階段, 然後執行mvn package spring-boot:run
。
如果需要,可以在 <Configuration>
元素中配置生效,例如,如果應用程式不使用 SpEL支援,則可以在構建時刪除 SpEL 支援來減少最終包的體積:
<configuration>
<removeSpelSupport>true</removeSpelSupport>
</configuration>
有關可用配置選項的列表,請參閱 Configuring Spring AOT。
4.1.1 Intellij IDEA
如果不採用 Maven 外掛的方式編譯執行,則可能需要按以下方式配置 Maven 目標的觸發器。
在 Maven 視窗中,轉到“外掛”並對映:
- 右鍵單擊
spring-aot:generate
然後單擊 "After build"。 - 新增 JUnit 配置(或者在執行第一個測試的時候),然後右鍵單擊
spring-aot:test-generate
, 接著單擊 "Execute Run/Debug …",最後選擇您的 JUnit 測試配置。
如果將構建/執行操作委託給 Maven,則它應該是開箱即用的。
4.1.2 Eclipse 和 VSCode
具有 m2e(Maven)或 Buildship(Gradle)的 Eclipse 應該是開箱即用的,直接使用 Spring AOT plugin 生成原始碼即可。
但是 Eclipse 不支援在 main 和 test 生成相同的類,因此預設情況下禁用測試源的生成,並且測試應在 IDE 裡以不使用 Spring AOT 外掛生成原始碼的情況下執行。
VSCode 使用了 Eclipse 的構建工具,因此它們是一樣的配置。
4.2 Gradle
在 settings.gradle(.kts)
檔案中首先宣告外掛:
Gradle Groovy
pluginManagement {
repositories {
// ...
maven { url 'https://repo.spring.io/release' }
}
}
Gradle Kotlin
pluginManagement {
repositories {
// ...
maven { url = uri("https://repo.spring.io/release") }
}
}
Gradle Groovy
plugins {
// ...
id 'org.springframework.experimental.aot' version '0.9.2'
}
Gradle Kotlin
plugins {
// ...
id("org.springframework.experimental.aot") version "0.9.2"
}
外掛建立兩個 SourceSets
用於測試和執行應用:"aot" 和 "aotTest"。當執行 test
,bootRun
和 bootJar
等任務時,最終的類程式碼和資原始檔會自動的新增到應用的執行時類路徑(runtime classpath of the application)。
原始碼生成在 build/generated/sources/aot/
,build/generated/resources/aot/
, 測試原始碼在 build/generated/sources/aotTest/
,build/generated/resources/aotTest/
。
如果需要,可以使用 springAot
DSL 擴充套件來執行配置,例如,如果您的應用程式不使用SpEL支援,則可以在構建時刪除 SpEL 優化最後的空間佔用:
Gradle Groovy
springAot {
removeSpelSupport = true
}
Gradle Kotlin
springAot {
removeSpelSupport.set(true)
}
這是完整的程式碼示例,包括所有預設值以及如何配置:
Gradle Groovy
import org.springframework.aot.gradle.dsl.AotMode
// ...
springAot {
mode = AotMode.NATIVE
debugVerify = false
removeXmlSupport = true
removeSpelSupport = false
removeYamlSupport = false
removeJmxSupport = true
verify = true
removeUnusedConfig = true
failOnMissingSelectorHint = true
buildTimePropertiesMatchIfMissing = true
buildTimePropertiesChecks = ["default-include-all","!spring.dont.include.these.","!or.these"]
}
Gradle Kotlin
import org.springframework.aot.gradle.dsl.AotMode
// ...
springAot {
mode.set(AotMode.NATIVE)
debugVerify.set(false)
removeXmlSupport.set(true)
removeSpelSupport.set(false)
removeYamlSupport.set(false)
removeJmxSupport.set(true)
verify.set(true)
removeUnusedConfig.set(true)
failOnMissingSelectorHint.set(true)
buildTimePropertiesMatchIfMissing.set(true)
buildTimePropertiesChecks.set(arrayOf("default-include-all","!spring.dont.include.these.","!or.these"))
}
Gradle Kotlin DSL 的
property.set(…)
不起作用, 原因看 gradle#9268。
有關配置選項的更多詳細資訊,參見 Configuring Spring AOT。
4.2.1 Intellij IDEA
在 Intellij IDEA 中執行或除錯應用程式:
轉到 Gradle工具視窗 → Tasks → application,然後右鍵單擊 bootRun
,選擇 "Run" 或 "Debug"。
4.3 配置 Spring AOT
mode
切換外掛真實為本地映象編譯器提供多少配置:native
(預設)提供本地映象以及代理的資源,初始化,代理和反射(使用自動配置提示)配置。native-init
如果僅希望提供初始化配置和替換,則應使用。native-agent
正在使用跟蹤代理程式生成的配置作為基礎,並且還為控制器等元件提供了其他提示。
removeXmlSupporttrue
預設情況下設定為true
,優化空間佔用,將其設定為false
恢復Spring XML
支援(XML converters, codecs and XML application context support)。removeSpelSupport
預設情況下設定為false
,設定為true
刪除 Spring SpEL 支援以優化空間佔用(應僅在不需要 SpEL 的應用中使用)。removeYamlSupport
預設情況下設定為false
,設定為則true
刪除Spring Boot Yaml支援以優化空間佔用。removeJmxSupport
預設情況下設定為true
,以優化空間佔用,將其設定為false
恢復 Spring Boot JMX支援。verify
預設情況下設定為true
,執行一些自動驗證以確保應用可以本地編譯, 設定為false
關閉驗證。debugVerify
預設設定為false
,設定為true
時啟用驗證除錯。removeUnusedConfig
預設情況下設定為true
,設定為false
禁用刪除未使用的配置。failOnMissingSelectorHint
預設情況下設定為true
,如果沒有為啟用的選擇器提供提示資料,則丟擲錯誤,設定為false
將外掛從丟擲錯誤切換為警告。有關更多詳細資訊,請參見 “故障排除” 部分。- [Experimental]
buildTimePropertiesMatchIfMissing
預設設定為true
。將其設定為false
意味著指定matchIfMissing=true
的任何屬性都將被覆蓋且不報錯。這將使應用程式進入一種模式,在這種模式下,它需要更明確地指定啟用配置的屬性(這是一個正在開發中的選項,嘗試用於映象大小和顯式屬性之間的權衡) - [Experimental]
buildTimePropertiesChecks
(實驗)開啟一些與屬性相關的配置條件構建時間的評估。它必須至少包含default-include-all
或default-exclude-all
的初始引數, 然後可以使用逗號分隔的字首列表,以明確包含或排除(例如default-include-all,!spring.dont.include.these.,!or.these
或default-exclude-all,spring.include.this.one.though.,and.this.one
)。字首匹配最長的屬性將會被應用(如果屬性與多個字首匹配)。
5. 本地化提示
GraalVM 原生映象支援通過靜態檔案進行配置,位於應用程式類路徑 META-INF/native-image
下的靜態檔案會被自動發現。檔案也可以是 native-image.properties
,reflect-config.json
,proxy-config.json
或 resource-config.json
。
Spring Native 通過 Spring AOT build plugin
自動生成配置檔案(與任何使用者的配置檔案並排放置)。但是,在某些情況下需要指定本地化的配置:
- 像
WebClientJackson
一樣的程式設計API中使用基於反射的序列化時 - 當您嘗試使用Spring Native尚不支援的功能或庫時
- 當您想要指定與您自己的應用程式相關的本機配置時。
這些都可以通過在已註解 @Configuration
或 @SpringBootApplication
的配置類上再添加註解 @NativeHint
實現,或者在簡單的配置類上直接添加註解 @TypeHint
(一個@NativeHint
是包括 @TypeHints
在內的多種配置的容器)。
例如,使用 WebClient
反序列化巢狀 SuperHero
的 Data
類:
@TypeHint(types = Data.class, typeNames = "com.example.webclient.Data$SuperHero")
@SpringBootApplication
public class WebClientApplication {
// ...
}
實際上,Spring Native 本身使用開箱即用的此類註解來配置您的大多數應用程式,browse them
檢視一些具體的提示示例。
這些提示將在編譯過程中考慮在內,並由 Spring AOT 外掛轉換並生成為本地化配置。當然,如果您願意,也可以直接提供 GraalVM 本地化配置檔案,但是基於註釋的配置通常更容易編寫和維護,這要歸功於自動完成和編譯型別檢查。
以下是特別提示的完整列表:
proxies
需要打包到映象中的代理列表。types
列出所有反射需求的列表。它應該使用類引用,但是如果可見性(私有類)阻止了類引用,則允許使用類的字串名稱。如果這些型別是通過JNI訪問的型別,並且應放入jni-config.json檔案中,而不是reflect-config.json確保在定義訪問時將訪問位JNI置位。serializables
通過@SerializationHint
註釋列表列出了所有序列化需求。resources
其中列出了與應該包含在映像中的資源(包括.class檔案)匹配的模式。initialization
其中列出了應該在構建時或執行時顯式初始化的類/程式包。不應真正在包含的提示上指定觸發器initialization。imports
如果兩個提示共享多個@TypeHint/ @ProxyHint/ etc,則很有用。例如,active-web和webmvc可能會公開許多常見的基礎結構。這些資訊註釋(TypeHint / ProxyHint / etc)可以放在兩個單獨的型別上,而不是在兩個地方重複,而imports可以引用該型別以將它們拉入特定的型別@NativeHint。
您可以檢視 the Javadoc
以獲得更多詳細資訊,還可以在 How to contribute
部分中檢視更多提供本地化配置的動態方法。
6. 示例專案
專案根目錄下的 samples
資料夾中有許多示例。
Maven專案可以使用每個示例目錄中存在 native-image
的 build.sh
指令碼檔案來構建和測試。Maven 或 Gradle 專案可以使用 Buildpack 支援來構建,該構建需要安裝 Docker , 使用 mvn spring-boot:build-image
或 gradle bootBuildImage
命令。
請注意,原生映象編譯可能會花費很長時間,並且會佔用大量記憶體。
這些示例顯示了執行良好的各種技術:帶有 Tomcat 的 Spring MVC,帶有 Netty 的 Spring WebFlux,Thymeleaf,JPA等。Petclinic 示例在一個應用程式中將多種技術結合在一起。
如果您開始構建第一個 Spring Boot 應用程式,我們建議您遵循其中一個上手指南。
7. 原生映象選項
GraalVM native-image
選項在 here 記錄。Spring Native會自動啟用其中的一些功能,另外一些特別有用的功能也會在此處記錄。
BP_NATIVE_IMAGE_BUILD_ARGUMENTS
如果使用Buildpacks支援,則可以使用Spring Boot外掛中的環境變數來指定它們;如果使用,<buildArgs></buildArgs>
則可以使用配置元素來指定它們 native-image-maven-plugin
。
7.1 預設啟用的選項
這些選項在使用 Spring Native 時預設啟用,因為當編譯為 GraalVM 原生映象時,它們是使 Spring 應用程式正常工作所必需的。
--allow-incomplete-classpath
允許使用不完整的類路徑構建映像,並在首次訪問它們時(而不是在構建映像時)在執行時報告型別解析錯誤。--report-unsupported-elements-at-runtime
報告不支援的方法和欄位在第一次訪問時在執行時的使用情況,而不是在映像構建期間顯示為錯誤。--no-fallback
強制僅本機映像執行時,並在常規JVM上禁用回退。--no-server
表示不要使用有時可能不可靠的映像構建伺服器,有關更多詳細資訊,請參見 graal#1952。--install-exit-handlers
允許對來自Docker的關閉請求做出反應。-H:+InlineBeforeAnalysis
啟用分析之前的內聯,以便允許實用程式方法返回常量,例如考慮刪除程式碼。
7.2 實用選項
--verbose
列印更詳細的構建過程-H:+ReportExceptionStackTraces
出錯的時候提供更多細節。--initialize-at-build-time
預設情況下在構建時初始化類,而未指定任何類或程式包。基於Netty的應用程式當前(希望是暫時)需要此選項,但其他應用程式不建議使用此選項,因為它會觸發相容性問題,尤其是有關日誌記錄和靜態欄位的問題。有關更多詳細資訊,請參見 this issue。如果需要,可以將其與特定的類或指定的包一起使用。-H:+PrintAnalysisCallTree
有助於查詢使用了哪些類,方法和欄位以及原因。您可以在 reports documentation 中找到更多詳細資訊。-H:ReportAnalysisForbiddenType=com.example.Foo
幫助查詢指定的類為什麼打包到了映象中。--trace-class-initialization
提供以逗號分隔的完整類名稱的列表,跟蹤其如何初始化的。--trace-object-instantiation
提供以逗號分隔的完整類名稱的列表,跟蹤物件如何例項化。--enable-all-security-services
加密和某些安全服務必需的(預設情況下,應在需要時由 Spring Native 通過 Native hints 啟用)。--enable-https
啟用HTTPS支援(比如使用WebClient
或RestTemplate
時通常需要)。
7.3 不支援的選項
--initialize-at-build-time
不支援未指定類或程式包的情況,因為預設情況下,Spring Native for GraalVM 旨在與執行時類初始化一起使用(在構建時啟用了一組選定的類)。
8. Tracing agent
GraalVM 原生映象 Tracing agent
允許攔截 JVM 上的反射,資源或代理,以生成相關的本地化配置。Spring Native 應該會自動生成大多數本地化配置,但是可以使用 Tracing agent
來快速識別丟失的條目。
兩種使用方法:
- 直接啟動應用程式並應用。
- 執行應用程式的測試程式碼並應用。
第一個選項對於在 Spring Native 無法識別庫或模式時識別缺少的本機配置很有趣。
請參閱此相關的 graal#3283
問題,該問題應使此過程更加容易。現在,您可以在 Spring Native 生成的本機配置與跟蹤代理生成的本機配置之間進行手動區分。
對於可重複的設定,第二個選項聽起來更有吸引力,但是預設情況下,生成的配置將包含測試基礎結構所需的任何內容,而在應用程式實際執行時則不需要此配置。為了解決此問題,代理支援訪問過濾器檔案,該檔案將導致某些資料從生成的輸出中排除。
8.1 Testing with the agent to compute configuration
8.1.1 基本的訪問過濾器檔案
一個簡單的 access-filter.json
檔案。
{ "rules": [
{"excludeClasses": "org.apache.maven.surefire.**"},
{"excludeClasses": "net.bytebuddy.**"},
{"excludeClasses": "org.apiguardian.**"},
{"excludeClasses": "org.junit.**"},
{"excludeClasses": "org.mockito.**"},
{"excludeClasses": "org.springframework.test.**"},
{"excludeClasses": "org.springframework.boot.test.**"},
{"excludeClasses": "com.example.demo.test.**"}
]
}
這些行中的大多數將適用於任何 Spring 應用程式,除了最後一個特定於應用程式的行,並且需要進行調整以匹配特定應用程式測試的程式包。
8.1.2 使用訪問過濾器檔案
使用 access-filter-file
選項將access-filter.json
檔案指定為 agentlib 字串的一部分:-agentlib:native-image-agent=access-filter-file=access-filter.json,config-output-dir=target/classes/META-INF/native-image
8.1.3 與 maven 一起使用
讓我們看看如何將這些想法融合在一起,並將其應用到專案中。
由於Spring在構建應用程式上下文時會採用急切的方法,因此啟動應用程式上下文的非常基本的測試將使用許多需要生成本機映像配置的Spring基礎結構。該測試就足夠了,可以放在src/test/java:
package com.example.demo.test;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class AppContextStartupTest {
@Test
public void contextLoads() {
}
}
現在access-filter.json
從上方取出檔案並將其放在 src/test/resources
資料夾中。
以下程式碼片段將進入Maven pom:
<plugins>
<!-- ... -->
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>create-native-image-config-folder</id>
<phase>test-compile</phase>
<configuration>
<target>
<mkdir dir="target/classes/META-INF/native-image"/>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-agentlib:native-image-agent=access-filter-file=src/test/resources/access-filter.json,config-merge-dir=target/classes/META-INF/native-image</argLine>
</configuration>
</plugin>
</plugins>
注意
maven-antrun-plugin
執行Surefire
之前建立本地映像配置目錄的宣告。GraalVM 21.1.0+不再需要此功能,請參閱 graal#3250 相關問題。
同時更新spring-aot構建外掛以啟用該native-agent模式:
<plugin>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-aot-maven-plugin</artifactId>
<configuration>
<mode>native-agent</mode>
</configuration>
</plugin>
就這樣了,構建原生映象應該在測試期間生成本地化配置,並與 native-agent
模式設計一起執行以新增缺失的二進位制資料。如果這還不夠,使用 @NativeHint
註解新增其他本地化配置。
9. 常見問題
在嘗試構建原生映象時,在嘗試啟動生成的映象時,各種各樣事情都可能出錯。通常,問題是缺少本機配置,因此請務必先檢查本機提示。閱讀本機映像參考文件也可能會有所幫助。
本節探討了可能遇到的一些錯誤以及可能的修復或解決方法。
在建立新的之前,請確保檢查與 Spring 相關的 GraalVM 原生映象已知問題以及Spring 本地化未解決的問題。
9.1 native-image
構建失敗
很多原因都可能導致失敗。這裡有一些最常見的原因及其解決方案。
9.1.1 在構建時意外初始化了 DataSize
如果您看到類似以下的錯誤:
Error: Classes that should be initialized at run time got initialized during image building:
org.springframework.util.unit.DataSize was unintentionally initialized at build time. To see why org.springframework.util.unit.DataSize got initialized use --trace-class-initialization
您可能已經嘗試將 Spring Boot 應用程式編譯為原生,而沒有 spring-native
依賴項和Spring AOT plugin
。請參閱 Getting started with native image Maven plugin 和 Getting started with Buildpacks。
9.1.2 警告:無法註冊反射元資料
這些警告目前是預期的,應該在將來的版本中刪除,有關更多詳細資訊 #502。
9.1.3 構建本機映像時出現記憶體不足錯誤
記憶體不足會出現錯誤訊息,大概長這樣Error: Image build request failed with exit status 137。
native-image
會消耗大量 RAM,因此建議您使用至少 16G RAM 的計算機。
如果使用的是容器,則在 Mac 上,建議將分配給 Docker 的記憶體增加到至少 8G(並可能還要新增更多的 CPU),因為native-image編譯器是一個繁重的過程。有關更多詳細資訊,請參見 Stackoverflow answer。
在 Windows上,請確保啟用 Docker WSL 2 後端以獲得更好的效能。
9.1.4 Builder 生命週期 'creator' 失敗,狀態碼為 145
這是由Docker觸發並由Spring Boot Buildpacks支援轉發的一般錯誤。native-image命令可能已失敗,因此請檢查輸出中的錯誤訊息。如果找不到任何內容,請檢查是否不是如上所述的記憶體不足錯誤。
9.2 生成的映象無法執行
如果生成的映像無法執行,本節介紹了一些可能的修復方案。
9.2.1 缺少資源包
在某些情況下,出現問題時,錯誤訊息將嘗試告訴您確切的操作,如下所示:
Caused by: java.util.MissingResourceException:
Resource bundle not found javax.servlet.http.LocalStrings.
Register the resource bundle using the option
-H:IncludeResourceBundles=javax.servlet.http.LocalStrings.
您應該使用 Native hints 新增資源配置。
9.2.2 執行mvn spring-boot:run
啟動失敗
手動執行 package
, 再使用 mvn package spring-boot:run
。
9.2.3 缺少配置
Spring AOT 外掛將盡可能捕獲所有內容,但是它不能理解所有程式碼,很多場景下需要自己編寫本地化配置,請參閱 Native hints,Tracing agent 和 How to contribute。
9.2.4 No access hint found for import selector: XXX
Provide hints for import selectors
9.3 和多模組專案協同工作
Spring Boot 和 AOT 外掛應僅應用於包含主應用程式類的模組。我們共享了一個示例應用程式,顯示瞭如何使用 Gradle 和 Maven 設定多模組專案。
9.4 使用快照版本
快照是定期釋出的,並且顯然在釋出和里程碑之前。如果您希望使用快照版本,則應使用以下儲存庫:
<repositories>
<!-- ... -->
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
</repository>
</repositories>
10. 如何貢獻
本節描述如何為Spring應用程式中使用的庫或功能貢獻本機支援。這可以通過將submit pull requests 提交給 Spring Native 來獲得 start.spring.io 支援的範圍來完成,或者通過直接在庫或應用程式級別上提供原生支援來完成。
10.1 設計原生友好的 Spring 庫
本機支援主要是使應用程式及其庫可以在構建時進行分析,以配置在執行時需要或不需要的內容。目的是以最佳方式做到這一點,以最小化佔用空間。
Spring應用程式是動態的,這意味著它們通常在各種地方使用Java語言功能(例如反射)。Spring Native及其Spring AOT構建外掛在特定的應用程式類路徑和配置的上下文中執行AOT轉換,以生成最佳的本機配置。它們還生成程式化版本spring.factories或自動配置,以減少執行時所需的反射量。
每個反射條目(每個構造器/方法/欄位)均通過導致建立代理類native-image,因此從佔用空間的角度來看,這些AOT轉換允許生成更小,更優化的配置。
下面的文件描述了嘗試使Spring程式碼與本機映像更加相容時要記住的最佳實踐。
10.1.1 用 proxyBeanMethods=false
或方法引數注入 @Configuration
類
在本機應用程式中,帶 @Bean
註釋的方法不支援交叉 @Bean
呼叫,因為它們需要在執行時建立的CGLIB代理。這類似於您通過所謂的lite模式或所獲得的行為@Configuration(proxyBeanMethods=false
)。
應用程式可以直接使用 @Configuration
而無需設定 proxyBeanMethods=false
和使用方法引數來注入 Bean 依賴關係,這是很好的選擇,這由 Spring Native 處理,不需要CGLIB代理。
鼓勵使用 @Configuration(proxyBeanMethods=false)
的庫(大多數 Spring 產品組合當前都使用此變數),因為通常最好避免使用 CGLIB 代理,以提供本地化相容性。在將來的 Spring Framework 版本中,此行為可能會成為預設行為。
10.1.2 將 NativeDetector 用於原生代碼路徑
與 Spring 相關的程式碼應使用 NativeDetector.inNativeImage()
(由程式包中的spring-core
依賴關係提供 org.springframework.core
)檢測特定於本機的程式碼路徑。Spring Framework 或 Spring Data利用此實用程式方法來禁用CGLIB代理,因為例如本機映像中不支援它們。
但是,在可能的情況下,我們建議編寫在兩種情況下都可以使用的程式碼,而不要總是依賴於 NativeDetector
,通用程式碼將更易於推理和測試/除錯。
10.1.3 在靜態塊/欄位中執行類路徑檢查並配置構建時初始化
可以在應用程式/依賴項中配置程式碼以在映像構建時執行。這將加快影象的執行時效能並減少佔用空間。
如果某些程式碼的行為以類路徑上存在某個類為條件,則可以在構建映像時執行該狀態檢查,因為在此之後無法更改類路徑。
通常通過嘗試以反射方式載入類來進行狀態檢查。如果可以在構建本機映像時執行檢查,那麼這是最佳選擇,那麼在執行時該狀態檢查不需要反射配置。要實現此優化:
- 在一種型別的靜態塊/欄位中執行狀態檢查。
- 使用以下命令配置包含要在構建時初始化的支票的型別 @NativeHint
必須注意儘可能限制在構建時可傳遞初始化的其他類的數量,因為它會引入嚴重的相容性問題。
10.1.4 儘可能嘗試使用功能性方法
對於在執行時執行的程式碼,請儘可能使用 lambda 和方法引用之類的功能方法,而不是儘可能使用反射,因為這些結構會被原生映象靜態分析自動理解。
例如,如果您的 Spring 專案正在使用 RootBeanDefinition
,則使用 Supplier
基於建構函式的構造器將是本機友好的,即 native-image
編譯器將理解 Bean 建立而無需本機反射配置。因此new RootBeanDefinition(BeanFactoryChannelResolver.class)
,使用代替 new RootBeanDefinition(BeanFactoryChannelResolver.class, BeanFactoryChannelResolver::new
)。有關更多詳細資訊,請參見 the related Javadoc。
10.1.5 儘可能將反射移到構建時
在本機環境中使用反射是很好的選擇,但是最好在構建時執行的程式碼中使用反射:
- 在構建時初始化的類的靜態塊/欄位中
- 在AOT轉換中作為Spring AOT構建外掛執行
隨著 Spring AOT 的成熟,將在 Spring AOT 提供更多指南。
10.1.6 提供有關匯入選擇器的提示
Spring Native追逐對其他配置(@Import
用法)的配置引用。但是,如果使用匯入選擇器,則意味著程式碼正在確定下一個匯入的配置應該是什麼,這很難遵循。Spring Native不會進行這種級別的分析(可能會變得非常複雜)。這意味著,儘管Spring Native可以告訴它遇到了一個選擇器,但它不知道選擇器需要反射訪問的型別或它引用的其他配置。
現在,Spring Native可以繼續執行,也許可以執行,或者在執行時崩潰。通常,由於缺少此資訊而導致事情出錯時所產生的錯誤是非常神祕的。如果選擇器正在執行“如果此型別在周圍,請將該配置返回以包含”,則它可能找不到某種型別(當它確實存在但未在影象中公開時)並且不包括某些關鍵配置。因此,Spring Native分析會盡早且快速失敗,這表明它不知道特定選擇器在做什麼。
要解決此問題,您應該新增一個提示,其中將相關的匯入選擇器指定為觸發器。例如,請參見此提示和相關的服務載入程式條目。
您可以通過設定臨時把這個硬錯誤變成警告failOnMissingSelectorHint選項,false在配置Spring AOT。
10.2 貢獻新的提示
在大多數情況下,Spring Native會了解Spring應用程式的工作方式-配置如何相互引用,如何例項化Bean等。但是,它有些無法理解的微妙之處,並填補了它依賴於提示的知識空白,它們告訴系統當應用程式中特定的自動配置或庫處於活動狀態時,為本機映像構建可能需要哪些額外的配置。
- 提示可能表明必須包括特定資源,或者需要對特定型別進行反思。
- 新增對Spring的新區域或庫的新版本的支援時,解決缺少提示的典型方法如下:
請注意,如果您的應用程式,當您嘗試構建它或執行錯誤-一個classnotfound,methodnotfound或類似的錯誤。如果您使用的是Spring,那麼我們沒有樣品,這很可能會發生。
嘗試確定哪些配置類導致需要進行反射訪問。通常,我們會進行一些搜尋以查詢對缺少的型別的引用,這些搜尋將指導我們進行配置。
如果已經有NativeConfiguration該配置的實現,請使用額外的型別資訊對其進行擴充。如果沒有,請建立一個,@NativeHint在其上附加一個以標識觸發配置和需要公開的類,然後將其新增到中META-INF/services/org.springframework.nativex.extension.NativeConfiguration。您可能還需要在註釋中(在中@TypeHint)設定可訪問性。可能需要將更多依賴項新增到配置專案中,以允許直接類引用。可以,只要您確保它們提供了作用域即可。
有關基本提示文件,請參閱本機提示。這些@NativeHint可以在以下兩個位置之一進行託管:
在spring-native-configuration模組中,您可以看到它們託管在實現org.springframework.nativex.extension.NativeConfiguration介面的型別上。此介面的實現應在src/main/resources/META-INF/services/org.springframework.nativex.type.NativeConfiguration檔案中列出,該功能通過常規Java服務載入來載入。
在Spring配置類上。這對於特定於專案的提示或在將示例移至spring-native-configuration模組之前製作示例提示時很有用(較短的反饋迴圈)。
一個attribute觸發器可以在指定@NativeHint的註釋。
如果提示在NativeConfiguration類上,並且未指定觸發器,則假定此配置應始終適用。這對於所有應用程式必需的通用配置很有用。
如果提示不在某個NativeConfiguration類上(例如,在Spring自動配置類上),則認為該型別是觸發器,並且如果Spring AOT外掛確定其為“活動”,則該提示適用。
該trigger屬性可能是Spring基礎結構的一部分(自動配置,匯入選擇器),也可能只是常規類。如果Spring AOT外掛確定在應用程式執行時Spring基礎結構可能處於活動狀態,或者(對於常規類觸發器)命名類位於類路徑中,它將啟用關聯的提示,從而通知本機映像構建過程是什麼。需要。
最佳實踐是使用樣本(現有樣本或新樣本)中的提示,以便對其進行自動測試。對所製作的提示滿意後,您可以提交請求請求。
使用 Tracing agent 還可以用於近似所需的本地配置,而不必執行太多本地版本。
10.3 動態本機配置
目前,由於相關API不夠穩定,因此僅作為Spring Native本身的一部分才支援提供動態本機配置。需要動態配置的外部庫現在可以實現GraalVM本機映像功能。
動態本機配置需要在中實現spring-aot。對於除錯,您可以使用mvnDebug或gradle -Dorg.gradle.debug=true --no-daemon並在您的IDE上8000通過Maven或5005Gradle在埠上與JVM遠端偵錯程式連線。
10.3.1 繼承實現 NativeConfiguration
有時,必要的配置很難靜態宣告,並且需要一種更動態的方法。例如,代理提示中涉及的介面可能需要檢查一些超出類的簡單存在的東西。在這種情況下,computeHints可以實現允許以更動態的方式計算提示的方法,然後將其與通過註釋靜態宣告的提示進行組合。
該NativeConfiguration介面包含幾個預設方法,可以實現這些預設方法以進行更多控制。例如,是否NativeConfiguration應啟用a的提示可能是一個更微妙的條件,即配置是否處於活動狀態。可以在實現中實現該isValid方法NativeConfiguration並執行更詳細的測試,從此方法返回false將停用關聯的提示。
10.3.2。通過處理器進行更多控制
在Spring應用程式中,將有許多活動元件(主應用程式,配置,控制器等)。為了計算native-image呼叫所需的配置,可能需要對這些元件進行更為複雜的特定於域的分析。可以實現幾個介面來參與該功能正在經歷的過程:
ComponentProcessor實施有機會處理元件並可能註冊新配置。例如,spring-data(via SpringDataComponentProcessor)使用它來對儲存庫以及通用簽名中用於計算反射/代理/資源提示的型別進行更深入的分析。
SpringFactoriesProcessor實現有機會處理從spring.factories檔案載入的鍵和值。目前允許他們進行過濾,但是將來可能會擴大。通過過濾,意味著它們可以以程式設計方式計算出對於某些spring.factory而言,其中一個值是沒有意義的(例如,通過分析類路徑內容),並決定放棄意味著不再對其進行任何處理。
10.4 使用基於容器的構建環境
為了易於複製的構建 spring-native
,專用的互動式 Docker 映像可用於本地開發(在Linux和Mac上進行了測試),並且還用於 CI:
graalvm-ce
:帶有 Ubuntu bionic + GraalVM 本機的基本映像,由 CI 每天構建,可從 Docker hub 獲得spring-native
:帶有graalvm-ce
構建專案所需的+實用程式的基本映像,可從Docker Hub獲得spring-native-dev
:通過構建的本地映像,run-dev-container.sh
旨在在主機和容器之間共享同一使用者。
要使用它:
- 安裝Docker。
- 如果您使用的是Linux,請將其配置為允許非root使用者。
- 在Mac上,請確保在Docker首選項資源選項卡中為其分配了足夠的記憶體,最好是10G或更多,否則在構建映像時可能會遇到記憶體不足的問題。
- 執行run-dev-container.sh以使用適用於執行spring-native構建指令碼的互動式外殼來執行Docker容器(請參閱下面的更多文件)。
- 第一次,它將下載CI構建的遠端託管映像。
- 當前目錄和Maven主目錄在主機(通常是IDE)和容器(可以在其中執行內部版本)之間共享。
10.4.1 run-dev-container.sh
run-dev-container.sh
使用互動式 shell 執行 Spring Native for GraalVM 開發容器。
run-dev-container.sh [options]
options:
-h, --help show brief help
-j, --java=VERSION specify Java version to use, can be 8 or 11, 11 by default
-g, --graalvm=VERSION specify GraalVM flavor to use, can be stable or dev, stable by default
-w, --workdir=/foo specify the working directory, should be an absolute path, current one by default
-p, --pull force pulling of remote container images
-r, --rebuild force container image rebuild
10.4.2 常規開發工作流程
- 在您的IDE中匯入根專案。
- 將您正在處理的示例作為一個單獨的專案匯入到您的IDE中。
- build.sh如果對功能部件,替換部件或配置模組進行了修改,請執行根專案(從主機或容器)。
- 確保native-image已PATH完成(通常通過使用SDKMAN切換到GraalVM安裝來完成)。
- build.sh從容器中執行正在處理的樣品。
測試各種樣本您還可以從容器中執行root,build.sh然後build-key-samples.sh(僅測試關鍵樣本)或build-samples.sh(測試所有樣本)。
10.5 指令碼
該native-image命令支援許多標誌,用於產生有關影象內容的資訊。但是,有時真正有用的是比較兩個影象。一個不存在的東西是什麼?有時,篩選大量產出是很棘手的。scripts資料夾提供了一些工具來幫助您解決此問題。
10.5.1 映象比較
首先是 -H:+PrintAOTCompilation
在編譯過程中列印日誌記錄資訊,看起來像這樣:
Compiling FieldPosition[] java.text.DecimalFormat.getNegativeSuffixFieldPositions() [Direct call from StringBuffer DecimalFormat.subformat(StringBuffer, Format$FieldDelegate, boolean, boolean, int, int, int, int)]
Compiling FieldPosition[] java.text.DecimalFormat.getPositiveSuffixFieldPositions() [Direct call from StringBuffer DecimalFormat.subformat(StringBuffer, Format$FieldDelegate, boolean, boolean, int, int, int, int)]
通常有成千上萬的行。通常我們開啟該選項native-image中pom.xml。輸出將輸出到stdout,我們的樣本將在其中捕獲target/native-image/output.txt。完成兩個構建後,我們可以使用此資料夾中的指令碼來生成樹差異:
editorDiff.sh java8build / target / native-image / output.txt java11build / target / native-image / output.txt 8-11.html
輸入是要比較的兩個收集的PrintAOTCompilation輸出,以及應該生成的HTML檔案的名稱(它將包含可導航樹)。然後只需開啟HTML檔案。