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

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

我谨代表团队以及所有做出贡献的人,非常高兴地宣布 Spring Native 0.11 的发布,它为 Spring Boot 2.6 提供了原生支持。这次雄心勃勃的发布是 Spring 团队五个月辛勤工作的成果,他们开发了一个全新的架构,将 Spring 对使用 GraalVM 创建原生可执行文件的支持提升到新的水平。您可以在 start.spring.io 上进行体验!

想了解更多关于 Spring Native 0.11 的信息,并在 Spring Developer Advocate Josh Long 的这个新的 Spring Tips 视频中观看它的实际应用。

全新的提前编译 (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 在运行时所做的事情。相反,它会分叉一个新进程,在构建时(不启动)创建和内省应用程序上下文。这允许使用 Spring Framework 在运行时所做的部分功能,并且在 Bean 定义级别上工作,这要准确得多。

运行时灵活性

在构建时进行这些优化意味着与常规的 Spring Boot 自动配置模型相比,运行时灵活性会降低。在运行已编译的 Spring Boot 应用程序时,您仍然可以更改 HTTP 端口或日志级别,但例如您无法使用配置文件在运行时添加新的 Bean。

因此,在 JVM 上,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));
           }
      });
   }
}

通过使用 `NativeConfigurationRegistry`,`NativeConfiguration` 扩展点已得到改进,以提供 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 中轻松调试将在原生模式下运行的代码(主应用程序或测试)。

第二个优势是更高的效率。目前,它提供了大约 **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 的原生支持,这与 JDK 端默认使用 Liberica 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 生态系统的更好原生支持。不再提供 GraalVM 的 Java 8 版本,因为它已过时,难以维护,但您仍然可以使用 GraalVM 的 Java 11 版本来编译大多数 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 社区所有即将举行的活动。

查看所有