GraalVM和Spring应用程序 [英] GraalVM and Spring Applications

查看:109
本文介绍了GraalVM和Spring应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

The GraalVM system apparently cannot compile a Spring application into a native image.

我们可以编译Spring应用程序的一个子集(例如,作为一个单独的库),然后将其与使用常规javac编译器编译的其余部分一起使用吗?

Can we compile a subset of the Spring application -- say, as a separate library -- and then use that with the remainder compiled using the usual javac compiler?

或者,如果我们从应用程序中遗漏了一些Spring功能?

Or maybe if we leave out some Spring features from our application?

还有其他可能性吗?

推荐答案

已经 OlegŠelajev指出,使用 GraalVM本机映像(其中是Spring Boot应用程序本机编译)是 GraalVM 的子项目,现在可能有限制,并且实现反应式Spring Boot Web应用程序的示例项目中1.5 seconds0.08 seconds

As Oleg Šelajev already stated, native compilation of Spring Boot apps with GraalVM Native Image (which is a sub project of GraalVM) is possible with limitations right now and is planned to be released with the Spring Framework’s 5.3 release in autumn 2020. With Native Image you're able to achieve similar advantages in memory footprint and startup time reduction as you get with using Quarkus.io, Micronaut etc. I was able to reduce memory footprint from around 500MB to 30MB and startup time from 1.5 seconds to 0.08 seconds in an example project implementing a Reactive Spring Boot Web app.

简而言之,如果您想在生产中使用该功能,则必须等待2020年末的最终Spring 5.3版本以及基于该功能的Spring Boot版本.如果您想开始尝试使用该功能,则可以立即开始.

In short, if you want to use that feature in production you have to wait for the final Spring 5.3 release in late 2020 and the Spring Boot release which is based upon it. If you want to already start using that feature experimentally, you can start right now.

======已更新为

====== Updated to spring-graalvm-native 0.7.0 release at June 10, 2020. =======

以下是基本步骤(2020年6月) ://github.com/spring-projects-experimental/spring-graalvm-native"rel =" nofollow noreferrer> spring-projects-实验项目spring-graalvm-native

Here are the basic steps (June 2020), derived from the latest docs of the spring-projects-experimental project spring-graalvm-native and this blog post I recently wrote (step 7 & 8 could be either achieved with a compile.sh bash script or with the help of the native-image-maven-plugin - both alternatives are explained below):

  1. 编写您的Spring Boot应用程序(例如从 https://start.spring.io 重新开始或使用现有应用程序)
  2. 在pom.xml中升级到最新版本的Spring Boot 2.3.x(不要从2.2或更低版本开始!)
  3. 在pom.xml中设置开始类元素
  1. Write your Spring Boot app (like starting over at https://start.spring.io or use an existing application)
  2. Upgrade to a recent Release of Spring Boot 2.3.x (do not start with 2.2 or lower!) inside your pom.xml
  3. Setting start-class element in pom.xml

稍后,native-image命令需要与@SpringBootApplication带注释的类的完全合格的类名完全相同.像这样在pom.xml的属性中定义它:

The native-image command later needs the exact fully qualified class name of your @SpringBootApplication annotated class. Define it in your pom.xml's properties like this:

<properties>
        ...
        <start-class>io.jonashackt.springbootgraal.SpringBootHelloApplication</start-class>
</properties>

  1. 禁止使用GCLIB代理

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

As GraalVM doesn't support GCLIB proxies, Spring Boot needs to use JDK proxies instead. Therefore use the proxyBeanMethods = false property of your @SpringBootApplication class:

@SpringBootApplication(proxyBeanMethods = false)
public class SpringBootHelloApplication {
    ...
}

  1. 安装GraalVM 20.1.0和GraalVM本机映像命令

最简单的方法是使用SDKMAN:

The easiest way to do this is to use 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

通过输入java -version(应列出GraalVM)和native-image --version来检查两者是否都能正常工作.有关更多详细信息,请参见此博客文章.

Check if both works correctly by typing java -version (GraalVM should be listed) and native-image --version. See this blog post for more details.

  1. 从运行时重定位注释类路径扫描以构建时间& 6.检测自动配置

这两个步骤都是由Spring Graal @AutomaticFeature为您完成的,稍后与native-image命令一起使用.由于@AutomaticFeature 已发布Spring Milestones存储库,我们可以简单地向我们的pom.xml添加一个依赖项(别忘了现在还添加Spring Milestones存储库,因为现在还没有通过Maven Central发行):

Both steps are done for you by the Spring Graal @AutomaticFeature used later with the native-image command. As the @AutomaticFeature was already released on Spring Milestones repository, we can simply add a dependency to our pom.xml (don't forget to also add Spring Milestones repository for now, since this isn't shipped via Maven Central right now):

<dependencies>
        <dependency>
            <groupId>org.springframework.experimental</groupId>
            <artifactId>spring-graalvm-native</artifactId>
            <version>0.7.0</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>

  1. 准备执行本机映像命令

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

In essence, we need to prepare configuration variables for native-image command, then build the app, expand the Spring Boot fat JAR & configure the classpath. I created a compile.sh that executes the necessary steps with 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

  1. 制作native-image命令并运行编译

现在,我们几乎已经准备好要制作的所有东西,并最终运行native-image命令.这是一个示例,该示例基于提到的实现反应式Spring Boot Web应用程序的示例项目.这是一个棘手的问题,它取决于您要编译为GraalVM本机映像的Spring Boot应用程序的类型!因此,最好的方法是从

Now we have mostly everything prepared to craft and finally run the native-image command. Here's an example, which is based on the mentioned example project implementing a Reactive Spring Boot Web app. This one is tricky right now and is dependend on the kind of Spring Boot app you want to compile as GraalVM Native Image! Therefor the best way is to get some inspiration from the example projects of the spring-graal-native project:

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.graal.remove-unused-autoconfig=true \
  -Dspring.graal.remove-yaml-support=true \
  -cp $CP $MAINCLASS;

最后通过./compile.sh执行bash脚本,然后喝杯咖啡!这需要一些时间,具体取决于您的硬件!在我后期的MBP 2017中,示例项目大约需要3-4分钟.如果一切顺利,您可以在/target/native-image/spring-boot-graal中找到本地编译的Spring Boot应用程序.只需使用以下命令即可运行它:

Finally execute the bash script via ./compile.sh and grab a coffee! This takes some time depending on your hardware! On my late MBP 2017 this takes around 3-4 minutes for the example project. If everything went fine, you'll find your natively compiled Spring Boot app in /target/native-image/spring-boot-graal. Simply run it with:

./target/native-image/spring-boot-graal

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

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

替代7& 8:native-image-maven-plugin

除了bash脚本(并描述了步骤7和8)之外,还有

Alternatively to the bash script (and described steps 7 & 8) there's also the native-image-maven-plugin. But please only use it, if you're really sure how to configure the native-image command - since it's execution is quite cumbersome right now (I'am sure there will be many improvements until late 2020). If you want to use the plugin, the steps instead of 7 & 8 are as follows:

  1. 添加spring-context-indexer依赖项

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

As the Spring @AutomaticFeature doesn't automatically explore the needed Spring Components while used by the native-image-maven-plugin (is this a bug?), we need to explicitely add the spring-context-indexer to do the job:

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-indexer</artifactId>
    </dependency>

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

It creates a target/classes/META_INF/spring.components file which then is picked up by the native image compilation process.

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

为了获取

In order to get the native-image-maven-plugin working, it is good practice to create a new Maven profile for the native image compilation (see this pom.xml for a fully working example):

<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.graal.remove-unused-autoconfig=true -Dspring.graal.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>

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

We need to add the spring-boot-maven-plugin again, because it prepares neccessary configuration for the native image plugin.

关键部分是buildArgs标记,它需要继承native-image命令的参数,如compile.sh脚本所示.与之相比,我们可以省去-cp $CP $MAINCLASS参数,因为该插件可以识别包括主类本身的类路径(仅当设置了第3步中的start-class标记时,才可以包含主类本身).为了将我们的artifactId用作生成的可执行映像名称,使用<imageName>${project.artifactId}</imageName>是一个好主意.

The crucial part is the buildArgs tag which needs to inherit the parameters for the native-image command as seen in the compile.sh script. Compared to that one we can leave out the -cp $CP $MAINCLASS parameter, since the plugin recognises the classpath including the mainclass itself (the latter only, if the start-class tag from step 3 is set). Using <imageName>${project.artifactId}</imageName> is a good idea in order to use our artifactId for the resulting executable image name.

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

Now simply execute the Maven profile via:

mvn -Pnative clean package

如果编译成功,请使用以下命令启动本机Spring Boot应用程序:

If the compilation succeeded, start your native Spring Boot app with:

./target/spring-boot-graal

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

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

如果您想在像TravisCI这样的CI服务器上运行本机映像编译,或者使用Docker进行编译,我可以建议这样做答案此博客文章.参见在TravisCI上运行的完整编译过程

If you want to run the native image compilation on a CI server like TravisCI or use Docker to do the compilation I could recomment this so answer and this blog post. See the full compile process in action on TravisCI also.

这篇关于GraalVM和Spring应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆