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:AOT 轉換的 Gradle 插件。
  • 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本機應用程序的實用概述。

RESTful Web服務入門指南的實用指南

創建新的 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

  1. Install SDKMAN
  2. 安裝 GraalVM : sdk install java 21.0.0.2.r8-grl for Java 8 or sdk install java 21.0.0.2.r11-grl for Java 11
  3. 使用最新的 JDK : sdk use java 21.0.0.2.r8-grlsdk use java 21.0.0.2.r11-grl
  4. 運行 gu install native-imagenative-image extensions 引入 JDK。

如果您使用的是 Microsoft Windows,則可以按以下步驟手動安裝 GraalVM 構建:

  1. 下載 GraalVM 21.0.0.2
  2. 設置適當的 JAVA_HOMEPATH
  3. 運行 gu install native-imagenative-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-imagepackage 階段中觸發插件:

<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

    • 支持 Logback,但不支持使用 logback.xml 進行配置,需要使用application.propertiesapplication.yml 對其進行配置,更多詳細信息見#625
    • 目前尚不支持Log4j2,請參閱 #115
  • 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 verifymvn package 時,會在 Maven 生命周期中自動調用 spring-aot:generateprocess-test-classes 階段)和 spring-aot:test-generateprepare-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"。當運行 testbootRunbootJar 等任務時,最終的類代碼和資源文件會自動的添加到應用的運行時類路徑(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-alldefault-exclude-all 的初始參數, 然后可以使用逗號分隔的前綴列表,以明確包含或排除(例如 default-include-all,!spring.dont.include.these.,!or.thesedefault-exclude-all,spring.include.this.one.though.,and.this.one)。前綴匹配最長的屬性將會被應用(如果屬性與多個前綴匹配)。

5. 本地化提示

GraalVM 原生鏡像支持通過靜態文件進行配置,位於應用程序類路徑 META-INF/native-image下的靜態文件會被自動發現。文件也可以是 native-image.propertiesreflect-config.jsonproxy-config.jsonresource-config.json

Spring Native 通過 Spring AOT build plugin 自動生成配置文件(與任何用戶的配置文件並排放置)。但是,在某些情況下需要指定本地化的配置:

  • WebClientJackson 一樣的編程API中使用基於反射的序列化時
  • 當您嘗試使用Spring Native尚不支持的功能或庫時
  • 當您想要指定與您自己的應用程序相關的本機配置時。

這些都可以通過在已注解 @Configuration@SpringBootApplication的配置類上再添加注解 @NativeHint 實現,或者在簡單的配置類上直接添加注解 @TypeHint(一個@NativeHint 是包括 @TypeHints 在內的多種配置的容器)。

例如,使用 WebClient 反序列化嵌套 SuperHeroData 類:

@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-imagebuild.sh腳本文件來構建和測試。Maven 或 Gradle 項目可以使用 Buildpack 支持來構建,該構建需要安裝 Docker , 使用 mvn spring-boot:build-imagegradle 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支持(比如使用 WebClientRestTemplate 時通常需要)。

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 pluginGetting 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 hintsTracing agentHow 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等。但是,它有些無法理解的微妙之處,並填補了它依賴於提示的知識空白,它們告訴系統當應用程序中特定的自動配置或庫處於活動狀態時,為本機映像構建可能需要哪些額外的配置。

  1. 提示可能表明必須包括特定資源,或者需要對特定類型進行反思。
  2. 添加對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 旨在在主機和容器之間共享同一用戶。

要使用它:

  1. 安裝Docker。
  2. 如果您使用的是Linux,請將其配置為允許非root用戶。
  3. 在Mac上,請確保在Docker首選項資源選項卡中為其分配了足夠的內存,最好是10G或更多,否則在構建映像時可能會遇到內存不足的問題。
  4. 運行run-dev-container.sh以使用適用於運行spring-native構建腳本的交互式外殼來運行Docker容器(請參閱下面的更多文檔)。
  5. 第一次,它將下載CI構建的遠程托管映像。
  6. 當前目錄和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文件。


免責聲明!

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



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