GraalVM和Spring应用程序

use*_*736 13 spring graalvm

GraalVM系统显然无法将Spring应用程序编译为本机映像.

我们可以编译Spring应用程序的一个子集 - 比如说,作为一个单独的库 - 然后使用通常的javac编译器编译的其余部分吗?

或者,如果我们从应用程序中省略一些Spring功能?

还有其他可能吗?

Séb*_*uze 49

我们(Spring 团队)刚刚发布了一篇非常详细的博客文章和一段视频,发布了Spring Native测试版,可能为这个问题提供了最新的答案。

它允许您通过 Spring Bootmvn spring-boot:build-imagegradle bootBuildImage命令使用 GraalVM 本机映像编译器将 Spring 应用程序编译为本机可执行文件,或者仅native-image通过native-image-maven-plugin.

在 38 毫秒内开始编译为本机映像的 Spring Boot 应用程序

使用它最有用的链接是start.spring.io,它现在提供 Spring Native 支持和参考文档的入门部分。

可在 start.spring.io 上获得 Spring Native 支持

确保正确配置Spring AOT Maven 和 Gradle 插件,这些插件是为您的 Spring 应用程序获得适当本机支持所必需的。

享受!


Ole*_*jev 36

这个问题的开头陈述有点模糊,所以很难正确地解决它.

GraalVM绝对可以编译Spring应用程序.GraalVM分配与普通JDK非常相似,它包括一个javac实用程序,一个java实用程序,可以添加到路径中并正常使用.您可以设置$JAVA_HOME环境变量以指向解压缩GraalVM分发的目录,添加$JAVA_HOME/bin到路径,并使用Maven或Gradle或任何其他构建工具以您通常的方式构建Spring应用程序.

GraalVM还可以运行Spring应用程序,由自身和其他JVM编译.如果你很好奇,这里有一个Spring应用程序的例子,它不仅在GraalVM上运行,而且还使用R来使用GraalVM多语言功能可视化数据图.

现在,我想你的意思是GraalVM能够创建一些Java程序的可执行本机映像.目前,GraalVM无法创建典型Spring应用程序的本机映像.这是因为GraalVM本机映像生成过程对它可以编译的Java程序有一些限制.也许主要问题是Spring的动态类加载.

有一个spring-fu项目,一个基于功能配置的实验性Kotlin微框架,旨在测试未来Spring Boot版本的新想法,目前正在尝试通过GraalVM编译成本机图像.

与此同时,GraalVM团队正在研究如何简化将Spring应用程序编译为本机映像以及支持比目前更多的Spring应用程序.一些限制将保留,因此您将始终能够构建一个不能用作GraalVM本机映像的Spring应用程序,但也许您将能够构建也可以工作的Spring应用程序.
目前尚不清楚这些变化的确切路线图.

这是一个SpringFramework问题跟踪器票,人们可以按照它来查看开发.


jon*_*ckt 5

正如Oleg Šelajev已经指出的那样,使用GraalVM Native ImageGraalVM 的子项目)本地编译 Spring Boot 应用程序现在是可能的,但有限制,并计划在 2020 年秋季与 Spring Framework 的 5.3 版本一起发布。随着机映像你能够实现内存占用和启动时间减少类似的优点。你用Quarkus.io得到,Micronaut等我能够从周围减少内存占用500MB,以30MB从和启动时间1.5 seconds,以0.08 seconds在一个示例项目实施一个响应式 Spring Boot Web 应用程序

简而言之,如果您想在生产中使用该功能,则必须等待 2020 年末的最终 Spring 5.3 版本以及基于它的 Spring Boot 版本。如果您想已经开始实验性地使用该功能,您可以立即开始

asciicast

====== 2020 年 6 月 10 日更新到spring-graalvm-native 0.7.0 版本。========

以下是基本步骤(六月2020年)从最新的文档导出了的弹簧项目,实验项目弹簧graalvm本地这个博客帖子我最近写的(步骤7,8可能是因为存在一个实现compile.shbash脚本或的帮助native-image-maven-plugin- 这两种选择解释如下):

  1. 编写您的 Spring Boot 应用程序(例如从https://start.spring.io 重新开始或使用现有应用程序)
  2. 在 pom.xml 中升级到 Spring Boot 2.3.x 的最新版本(不要从 2.2 或更低版本开始!)
  3. 在 pom.xml 中设置 start-class 元素

native-image命令稍后需要带@SpringBootApplication注释的类的完全限定类名。在您pom.xml的属性中定义它,如下所示:

<properties>
        ...
        <start-class>io.jonashackt.springbootgraal.SpringBootHelloApplication</start-class>
</properties>
Run Code Online (Sandbox Code Playgroud)
  1. 禁用 GCLIB 代理的使用

由于 GraalVM 不支持 GCLIB 代理,因此 Spring Boot 需要使用 JDK 代理。因此,请使用proxyBeanMethods = false您的 @SpringBootApplication 类的属性:

@SpringBootApplication(proxyBeanMethods = false)
public class SpringBootHelloApplication {
    ...
}
Run Code Online (Sandbox Code Playgroud)
  1. 安装 GraalVM 20.1.0 和 GraalVM Native Image 命令

最简单的方法是使用 SDKMAN:

curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk install java 20.1.0.r11-grl
gu install native-image
Run Code Online (Sandbox Code Playgroud)

通过键入java -version(应列出 GraalVM)和native-image --version. 有关更多详细信息,请参阅此博客文章

  1. 将 Annotation 类路径扫描从运行时重新定位到构建时间 & 6. 检测自动配置

这两个步骤都是由稍后与native-image命令一起使用的 Spring Graal @AutomaticFeature 为您完成的。由于@AutomaticFeature已经在 Spring Milestones 存储库上发布,我们可以简单地向我们的pom.xml(不要忘记现在还添加 Spring Milestones 存储库,因为它现在不是通过 Maven Central 提供):

<dependencies>
        <dependency>
            <groupId>org.springframework.experimental</groupId>
            <artifactId>spring-graalvm-native</artifactId>
            <version>0.7.1</version>
        </dependency>
        ...
        <dependencies>
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
        </pluginRepository>
    </pluginRepositories>
Run Code Online (Sandbox Code Playgroud)
  1. 准备本机图像命令执行

本质上,我们需要为native-image命令准备配置变量,然后构建应用程序,扩展 Spring Boot fat JAR 并配置类路径。我创建了一个compile.sh,它使用 bash 执行必要的步骤:

#!/usr/bin/env bash

echo "[-->] Detect artifactId from pom.xml"
ARTIFACT=$(mvn -q \
-Dexec.executable=echo \
-Dexec.args='${project.artifactId}' \
--non-recursive \
exec:exec);
echo "artifactId is '$ARTIFACT'"

echo "[-->] Detect artifact version from pom.xml"
VERSION=$(mvn -q \
  -Dexec.executable=echo \
  -Dexec.args='${project.version}' \
  --non-recursive \
  exec:exec);
echo "artifact version is '$VERSION'"

echo "[-->] Detect Spring Boot Main class ('start-class') from pom.xml"
MAINCLASS=$(mvn -q \
-Dexec.executable=echo \
-Dexec.args='${start-class}' \
--non-recursive \
exec:exec);
echo "Spring Boot Main class ('start-class') is '$MAINCLASS'"

echo "[-->] Cleaning target directory & creating new one"
rm -rf target
mkdir -p target/native-image

echo "[-->] Build Spring Boot App with mvn package"
mvn -DskipTests package

echo "[-->] Expanding the Spring Boot fat jar"
JAR="$ARTIFACT-$VERSION.jar"
cd target/native-image
jar -xvf ../$JAR >/dev/null 2>&1
cp -R META-INF BOOT-INF/classes

echo "[-->] Set the classpath to the contents of the fat jar & add the Spring Graal AutomaticFeature to the classpath"
LIBPATH=`find BOOT-INF/lib | tr '\n' ':'`
CP=BOOT-INF/classes:$LIBPATH
Run Code Online (Sandbox Code Playgroud)
  1. 制作 native-image 命令并运行编译

现在我们已经准备好制作并最终运行native-image命令的所有东西。这是一个示例,它基于上述示例项目,实现了一个 Reactive Spring Boot Web 应用程序。这个现在很棘手,取决于你想要编译为 GraalVM Native Image 的 Spring Boot 应用程序的类型!因此,最好的方法是从spring-graal-native 项目的示例项目中获得一些灵感:

GRAALVM_VERSION=`native-image --version`
echo "[-->] Compiling Spring Boot App '$ARTIFACT' with $GRAALVM_VERSION"
time native-image \
  -H:+TraceClassInitialization \
  -H:Name=$ARTIFACT \
  -H:+ReportExceptionStackTraces \
  -Dspring.native.remove-unused-autoconfig=true \
  -Dspring.native.remove-yaml-support=true \
  -cp $CP $MAINCLASS;
Run Code Online (Sandbox Code Playgroud)

最新的文档这篇博文中还有对每个参数的全面解释。

最后通过执行 bash 脚本./compile.sh并喝杯咖啡!这需要一些时间,具体取决于您的硬件!在我 2017 年后期的 MBP 上,示例项目大约需要 3-4 分钟。如果一切顺利,您将在/target/native-image/spring-boot-graal. 只需运行它:

./target/native-image/spring-boot-graal
Run Code Online (Sandbox Code Playgroud)

==============================

7 & 8 的替代方案:native-image-maven-plugin

除了 bash 脚本(以及描述的步骤 7 和 8),还有native-image-maven-plugin。但是,如果您真的确定如何配置native-image命令,请仅使用它- 因为它现在的执行非常麻烦(我确信到 2020 年末会有很多改进)。如果要使用插件,代替7&8的步骤如下:

  1. 添加 spring-context-indexer 依赖

由于 Spring @AutomaticFeature 在使用时不会自动探索所需的 Spring 组件native-image-maven-plugin(这是一个错误吗?),我们需要明确地添加spring-context-indexer来完成这项工作:

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-indexer</artifactId>
    </dependency>
Run Code Online (Sandbox Code Playgroud)

它创建一个target/classes/META_INF/spring.components文件,然后由本机图像编译过程选取。

  1. 将 native-image-maven-plugin 添加为 Maven 构建配置文件

为了让native-image-maven-plugin正常工作,最好为本地图像编译创建一个新的 Maven 配置文件(请参阅此 pom.xml 以获得完整的工作示例):

<profiles>
    <profile>
        <id>native</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.graalvm.nativeimage</groupId>
                    <artifactId>native-image-maven-plugin</artifactId>
                    <version>20.1.0</version>
                    <configuration>
                        <buildArgs>-H:+TraceClassInitialization -H:+ReportExceptionStackTraces -Dspring.native.remove-unused-autoconfig=true -Dspring.native.remove-yaml-support=true</buildArgs>
                        <imageName>${project.artifactId}</imageName>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>native-image</goal>
                            </goals>
                            <phase>package</phase>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>
Run Code Online (Sandbox Code Playgroud)

我们需要spring-boot-maven-plugin再次添加,因为它为原生图像插件准备了必要的配置。

关键部分是buildArgs需要继承native-image命令参数的标签,如compile.sh脚本中所示。与那个相比,我们可以省略-cp $CP $MAINCLASS参数,因为插件识别包括主类本身的类路径(如果start-class设置了第 3 步中的标签,则只有后者)。<imageName>${project.artifactId}</imageName>为了使用 ourartifactId作为结果的可执行映像名称,使用是一个好主意。

现在只需通过以下方式执行 Maven 配置文件:

mvn -Pnative clean package
Run Code Online (Sandbox Code Playgroud)

如果编译成功,请使用以下命令启动您的原生 Spring Boot 应用程序:

./target/spring-boot-graal
Run Code Online (Sandbox Code Playgroud)

==============================

如果你想在像 TravisCI 这样的 CI 服务器上运行本机图像编译或使用 Docker 进行编译,我可以推荐这个答案这篇博文。另请参阅TravisCI 上完整编译过程