新的 AOT 引擎将 Spring Native 推向新高度

工程 | Sébastien Deleuze | 2021 年 12 月 9 日 | ...

我代表团队和所有贡献者,很高兴宣布 Spring Native 0.11 版本发布,它为 Spring Boot 2.6 提供了原生支持。这个雄心勃勃的版本是 Spring 团队五个月辛勤工作的结果,他们一直在开发一个全新的架构,以将 Spring 对使用 GraalVM 创建原生可执行文件的支持提升到新的水平。您已经可以在 start.spring.io 上试用它了!

在 Spring Developer Advocate Josh Long 的这部新 Spring Tips 视频中,了解更多关于 Spring Native 0.11 的信息并观看实际演示。

新的预编译(AOT)引擎

毫无疑问,最大的变化是引入了一个新的 AOT 引擎,它在构建时对您的 Spring 应用程序进行深度分析,以转换和优化您的应用程序,并生成所需的 GraalVM 原生配置。这些转换由 Maven 和 Gradle Spring AOT 插件执行。

spring boot native

深入来看,AOT 引擎在构建时评估条件,以便生成一个经过优化的应用程序上下文和 Spring factories(Spring Boot 背后的插件系统),这些都专门为您的应用程序量身定制。实际上,这意味着

  • 运行时需要执行的 Spring 基础设施更少

  • 运行时需要评估的条件更少

  • 更少的反射,因为使用了编程式 Bean 注册

AOT 引擎根据标识为活动的 Bean、Spring 编程模型的知识以及 Spring Native 捆绑的或您的应用程序自身提供的原生提示,推断出将您的应用程序作为原生可执行文件运行所需的原生配置。

aot architecture

我们要特别感谢 Stéphane Nicoll,他领导了这款新 AOT 引擎的设计和实现。

减少内存占用

AOT 引擎的一个关键优势在于它支持更小的原生可执行文件内存占用,因为原生配置更加精确,所需的反射更少,并且运行时所需的 Spring 基础设施更少。

相比 Spring Native 0.10,Spring Native 0.11 平均可减少 20%26% 的内存占用!下图展示了一些示例应用程序的数据点

native rss

更快的启动速度

相比 0.10 版本,Spring Native 0.11 的启动时间快了 16%35%,因为一些处理已从运行时移至构建时。由于在此次小版本更新中未能对 Spring Boot 和 Spring Framework 的内部架构进行精细调整,因此仍有改进空间。

native startup

改进的兼容性

AOT 引擎也更加精确,因为它不会试图分析 Spring 注解或各种类型来复制 Spring 在运行时所做的工作。相反,它会启动一个新的进程,在构建时创建并内省(introspect)应用程序上下文(而不启动它)。这允许使用 Spring Framework 在运行时执行的一部分功能,并在 Bean 定义层面工作,这要精确得多。

运行时灵活性

在构建时执行这些优化意味着运行时灵活性不如常规的 Spring Boot 自动配置模型。您在运行已经编译好的 Spring Boot 应用程序时,仍然可以更改 HTTP 端口或日志级别,但例如,您无法在运行时通过使用 Profile 来添加新的 Bean。

这就是为什么在 JVM 上,AOT 模式是可选的。如果它符合您的需求,这是一个可以使用的优化。在原生应用程序中(其设计决定了运行时动态性较低),AOT 是强制性的。此外,请记住,目前条件是在构建时评估的。我们将来可能会使其更灵活,以便适应大多数用例。

扩展点

新引擎提供了一个可插拔的模块化架构,用户(如您或 Spring 项目团队)可以使用它来支持各种新功能。

例如,请参阅 BeanFactoryNativeConfigurationProcessor 扩展点的这个实现,它会自动为标注了 @RequestScope@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) 注解的 Bean 预先创建类代理。

public class ScopeNativeConfigurationProcessor implements BeanFactoryNativeConfigurationProcessor {

   @Override
   public void process(ConfigurableListableBeanFactory beanFactory, NativeConfigurationRegistry registry) {
       new BeanFactoryProcessor(beanFactory).processBeansWithAnnotation(Scope.class, (beanName, beanType) -> {
           Scope scope = beanFactory.findAnnotationOnBean(beanName, Scope.class);
           if (scope.proxyMode() == ScopedProxyMode.TARGET_CLASS) {
               registry.proxy().add(NativeProxyEntry.ofClass(beanType, ProxyBits.NONE,
                       ScopedObject.class, Serializable.class, AopInfrastructureBean.class));
           }
      });
   }
}

NativeConfiguration 扩展点也得到了改进,通过使用 NativeConfigurationRegistry 提供了 API。

public interface NativeConfiguration {
   default boolean isValid(AotOptions aotOptions) { return true; }
   default void computeHints(NativeConfigurationRegistry registry, AotOptions aotOptions) { return; }
}

这些扩展点在 META-INF/spring.factories 中定义并被发现,因此您可以提供自己的实现

AOT 测试支持

我们在 Spring Native 0.11 上的大部分工作都集中在实现对 AOT 代码路径的测试支持,以便将原生测试支持提升到全新的水平。结果是兼容性得到了显著提升,支持更多种类的测试。

结合 Native Build Tools 提供的出色的 JUnit 5 原生支持,您可以像在 JVM 上一样运行您的 Spring Boot、Spring Framework 或纯 JUnit 测试。

与 Spring 无关,Mockito 尚未支持,但正在进行相关工作,使其将来成为可能。

JVM 上的 AOT

在 JVM 上运行的应用程序进行 AOT 转换有两个主要好处。

第一个好处是,例如,您可以在 IDE 中轻松调试将在 JVM 上原生运行的代码(主应用程序或测试)。

第二个优势是效率更高。目前,它可以提供大约 4%17% 更小的内存占用。

jvm rss

AOT 模式还能将应用程序启动速度加快 3%24%

jvm startup

请注意,到目前为止,我们还没有特别关注 JVM 的效率,因此在未来的版本中很可能有改进的机会。

Bellsoft Liberica NIK

Bellsoft Liberica Native Image Kit (NIK) 是一个基于 GraalVM 开源仓库和 Liberica JDK 的原生镜像编译器发行版。从 Spring Native 0.11 开始,它默认用于 Buildpacks 的原生支持,这与默认使用 Liberica JDK 的 JDK 端保持一致。也可以通过其 SDKMAN 集成或下载安装它来在本地安装。

今年早些时候,团队与 BellSoft 一起宣布,使用 Liberica Native Image Kit 的 VMware 客户可以将其 Spring 应用程序作为原生可执行文件运行,并且确信它们得到了全面支持。

新的基线

Spring Native 0.11 也为我们提供了一个基于 Spring Boot 2.6 的新基线。

GraalVM 21.3 同时支持 Java 11 和 Java 17,并利用条件式原生配置及其他相关优化,以实现更小的内存占用和对 JVM 生态系统更好的原生支持。Java 8 版本的 GraalVM 不再提供,因为它太老了,无法合理维护,但您仍然可以使用 Java 11 版本的 GraalVM 编译大多数 Java 8 应用程序。Native Build Tools 0.9.8 得到了支持,我们继续合作对其进行改进和优化。

Spring Boot 3 的一流原生支持

我认为 Spring Native 0.11 实现了其为 Spring Boot 提供成熟原生选项的目标。Spring 团队现在可以专注于下一个主要步骤:将精炼的原生支持作为 Spring Framework 6、Spring Boot 3 和相关项目组合的一部分。

请记住,我们在 Spring Native 上所做的一切都是与其他 Spring 项目密切合作完成的,但没有进行深入的架构更改。随着 AOT 和原生支持成为 Spring Boot 3 和 Spring Framework 6 的主要主题,这些功能的质量、可维护性和易用性将达到一个新的水平。AOT 引擎将得到精炼并直接集成到 Spring Framework 中。其他项目,如 Spring Data 或 Spring Security,将能够为其范围提供原生支持(并进行测试),而 Spring Boot 将在其插件和文档中提供开箱即用的 AOT 和原生可执行文件支持。

boot3 aot architecture

我们与 GraalVM 团队和 JVM 生态系统的合作将增加,以便为 Spring 之外的各种库提供原生配置,这些配置可以直接放在这些库中,也可以放在直接集成到 Native Build Tools 层面的原生配置仓库中。

我们计划在 2022 年 5 月发布的 Spring Boot 3 milestone 3 中开始提供开箱即用的 GraalVM 原生支持,充分利用我们在 Spring Native 工作中学到的所有经验。通用版本预计于 2022 年底发布。我们有许多令人兴奋的计划,但现在,让我们与 Spring 团队成员和做出贡献的 Spring 社区成员一起庆祝本次发布。干杯!

订阅 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

快人一步

VMware 提供培训和认证,助您加速进步。

了解更多

获取支持

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

了解更多

近期活动

查看 Spring 社区的所有近期活动。

查看全部