Spring GraalVM Native 0.6.0 版本发布

工程 | Andy Clement | 2020年4月9日 | ...

Spring 团队刚刚发布了 spring-graalvm-native 项目的 0.6.0 版本。该项目旨在简化构建 Spring 应用的 GraalVM 原生镜像的过程。

如需深入了解 Spring 的原生镜像,请观看 Sébastien Deleuze 在 Devoxx 大会上的演讲

在这篇博文中,我们将讨论自上次发布以来的变化,并向您指出一些关键资源,以便您可以尝试使用它!此项目位于 spring-projects-experimental github 组织中,表明它仍在开发中,但我们有很多示例应用程序展示了已经可以工作的技术类型,以及大量关于如何使用您自己的应用程序进行实验的文档。

什么是 GraalVM 原生镜像?

简单回顾一下,GraalVM 是一个大型项目,可以用于多种用途,但我们将重点关注的是将其用作将 JVM 代码运行为原生镜像。一旦编译为特定平台的原生镜像,应用程序应该具有非常快的启动速度和更可靠的内存配置文件(没有 JIT 导致启动时内存峰值)。

创建镜像时,原生镜像构建工具需要了解有关应用程序的信息,例如正在加载哪些资源,哪些类型可能会被反射,以及在构建镜像时可以安全地初始化类型还是必须在运行时稍后初始化。这些信息使原生镜像工具能够尝试为应用程序构建最佳镜像。

实际上,收集和交流此配置的方法有几种

  • 一些库将其直接包含在其分发版中,作为固定的 .json 文件(例如 netty)
  • 第三方功能(在 GraalVM 术语中)参与构建过程,计算信息并通过 API 将其传递给原生镜像。spring-graalvm-native 项目的一个关键方面是它包含的功能。此功能了解 Spring Boot 应用程序的运行方式,将该知识应用于正在构建的特定应用程序,并将结果传递给原生镜像构建过程。它可以做出非常动态的决策,因为它可以在封闭世界假设下运行,知道在镜像构建时类路径是完整/固定的。
  • GraalVM 提供的代理可以收集应用程序正常运行(作为 JVM 应用程序)时所需的配置数据,然后这些文件会在随后的原生镜像构建步骤中被拾取。

每种计算配置的方法都有其优缺点。例如,代理只能收集在应用程序运行时已执行的代码路径上的信息,但它肯定会创建一组精确所需内容的最佳设置(在资源/反射访问方面)。另一方面,该功能不会创建完全最佳的配置,因为它不会运行应用程序,因此必须允许可能采用也可能不采用的某些代码路径,但作为构建过程的一部分,该功能能够执行 Spring 特定的优化,例如提前评估条件配置。当原生镜像构建运行时,完整的类路径是已知的,因此可以在那时执行 @ConditionalOnClass 检查,如果失败,则可以丢弃该配置,甚至在生成的镜像启动时也不会查看。

我们一直在努力改进所有这些方面,试图改进生态系统,以便我们可以转向一个一切都能正常工作的世界。仍然有一些路要走!我们正在深入研究 Tomcat,以使其配置像使用 netty 一样容易。与 GraalVM 团队一起,我们一直在确保 Spring Boot 应用程序中没有任何内容会阻碍原生镜像构建(需要双方进行修复),并改进 spring-graalvm-native 功能以更好地理解更广泛的 Spring 应用程序。我们还一直在帮助确保代理收集器不会错过任何内容。我们目前正在与 GraalVM 团队一起处理的问题实际上是在 这里 跟踪。

自从在 2019 年 Spring One Platform 和 Devoxx 大会上演示以来,该功能对 Boot 的了解有所提高,代理缺失更少,GraalVM 兼容性更好,生成的镜像大小已减小,镜像构建时间已改进,我们还包含了更多示例项目来演示哪些内容正在工作。

如何尝试它?

这里有许多示例项目 这里,甚至包括 PetClinic(当然!)以及关于如何使用它们的示例相关文档 这里。有使用 Netty、Tomcat、Spring MVC、Spring WebFlux、JPA、Spring Cloud Function、Kotlin 等的示例。您可能会看到什么?

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::
...
INFO: Started TomcatApplication in 0.044 seconds (JVM running for 0.62)

要将其应用于您自己的项目,文档描述了使用 功能代理 或同时包含两者的 混合模式 的所有步骤。混合模式有时是两全其美的选择,因为代理可以捕获功能可能错过的内容,反之亦然。

如果它不起作用怎么办?

此过程还不是非常流畅,许多领域还有待改进。负责该功能的团队和 GraalVM 团队一直在努力改进诊断功能,以便在出现问题时,您仍然可以取得进展并了解下一步该做什么。某些随机应用程序不太可能第一次就能运行,但对于任何致力于解决问题的用户来说,许多应用程序都能运行。您的应用程序可能使用了我们测试中尚未遇到的库。它可能使用了该功能尚未了解的某些 Spring 行为。它可能在镜像构建时或编译镜像启动时运行时出错。 这里 有一个故障排除页面,讨论了一些常见问题以及如何解决这些问题。遇到其他问题?请在项目上 提出问题

spring-graalvm-native 项目中,有一个配置子项目,它试图以易于扩展的形式封装有关 Spring Boot 行为的知识。例如,它对特定的导入选择器可能会导致需要对特定类型进行反射访问进行编码。该功能本身是由这种封装的知识驱动的,如果您发现当前知识不足,请随时对其进行增强并贡献回项目以构建该知识,请参阅 可扩展性指南

spring-graalvm-native 项目中还包含一些替换,替换是 GraalVM 的一个术语,用于在镜像构建时更改现有的类,这些类在包含在原生镜像中时当前无法正常工作。随着时间的推移,计划仍然是消除这些问题,并与包含这些有问题的类的项目合作,使它们成为可以在原生镜像内或外工作的理想形式。

尽管spring-graalvm-native主要面向Spring,但很明显,一个Spring项目通常包含许多第三方依赖项。其中许多依赖项尚未包含必要的配置,因此我们的功能尽最大可能“弥补”它们的不足。我们的计划尽可能地与这些依赖项提供商合作,帮助他们创建理想的native-image配置,然后它将被native-image构建自动拾取。GraalVM代理提供了一种很好的方法来尝试处理缺少配置的代码。

未来展望

所有工作都只发生在这个实验性功能中吗?远非如此。Spring中已经进行了一些增强,以确保它在构建到native-image时能够正常运行。例如,在Spring Framework中,Spring Framework 5.2中的@Configuration proxyBeanMethods属性使应用程序能够在没有CGLIB代理的情况下运行(native-image进程只能支持JDK代理)。我们还重构了Spring Boot条件处理中的一些类加载,以使用不同的方法,因为代理无法捕获原始的加载形式。

更多此类增强功能即将推出。该功能还有更多内容需要学习,而在核心Spring中,启动时仍然做了太多事情,我们可以将其推迟到构建时,这将严重影响构建的native-image的内存需求。这些改进不仅将使构建到native-image的应用程序受益,而且还将使在常规JVM上运行的应用程序受益。情况只会越来越好!感谢GraalVM团队支持我们这项工作。要跟踪我们的进度,请关注该项目

订阅Spring新闻

关注Spring新闻

订阅

抢先体验

VMware提供培训和认证,助您快速提升。

了解更多

获取支持

Tanzu Spring在一个简单的订阅中提供OpenJDK™、Spring和Apache Tomcat®的支持和二进制文件。

了解更多

即将举行的活动

查看Spring社区中所有即将举行的活动。

查看全部