Spring Framework 6.0.0-M3 中的初步 AOT 支持

工程 | Stéphane Nicoll | 2022 年 3 月 22 日 | ...

了解 Spring Native 实验性项目的人都知道,Spring 团队自 2019 年以来一直在为 Spring 应用提供原生镜像支持。继 2021 年 3 月 发布首个 Beta 版 后,我们于 2021 年 12 月对 Spring Native 项目进行了 重大修订

我们还在去年 SpringOne 大会上宣布,我们打算在 2022 年将这项工作正式纳入 Spring Framework 6.0。继第三个里程碑版本发布后,这篇博文将向您介绍已经包含的内容以及后续的计划。

预先处理 (Ahead-Of-Time Processing)

预先处理应用上下文为优化打开了许多大门。根据具体上下文,我们可以减少随应用发布的底层设施数量,预先计算您在组件上声明的某些特性以加快启动时间,并识别在受限环境中可能出现问题的事项并为其提供替代方案。

Spring Framework 6.0.0-M3 发布了基于 Spring Native 的第一批此类特性,并经过了广泛审查并集成到核心容器中。它不是以附加模块的形式作为新特性,而是深度集成到现有核心模块中。目前包含:

  • 一个引擎,它针对给定的类路径处理 ApplicationContext,并生成提供优化版本上下文的代码。
  • 一个新的 API 用于提供运行时提示 (runtime hints):集成者通常在自己的组件需要使用反射,或者需要访问类路径上的特定资源时会使用此 API。这些提示与 GraalVM 兼容,我们提供了基础设施来生成相应的配置文件。

在构建时优化应用

当典型的 Spring 应用运行时,应用上下文会调用许多后处理器来准备 Bean 工厂:配置类解析、类路径扫描以及其他最终可能触发自动配置解析的处理器。一旦这些处理器运行完毕,在大多数情况下,它们在运行时就不再需要了。

在环境(类路径等)定义清晰的情况下,这可以在构建时完全完成,以便只有与当前环境相关的 Bean 定义被贡献到 Bean 工厂。在构建时运行的后处理器会被丢弃,并由它们贡献的代码替代。

有许多方法可以“预先”贡献代码,从注解处理到字节码生成。我们选择让新引擎生成 Java 源代码,并在构建期间将其贡献给应用。我们相信这在开发者体验和优化机会之间取得了恰当的平衡。

这不仅应以熟悉和透明的方式支持原生用例,我们还相信这将在未来为普通的 JVM 应用带来好处。例如,AOT 引擎完全独立于原生,因此您可以在 JVM 上验证应用的优化版本是否正常工作。

运行时提示 (Runtime Hints)

与 JVM 不同,运行原生镜像在某些场景下需要额外的配置。例如,如果您的代码通过反射调用方法,您需要进行说明,以便必要的底层设施被包含在原生镜像中。或者,如果您需要读取类的元数据(核心容器在启动时经常这样做),您需要将类的字节码包含进来,这可能导致镜像大小显著增加。

AOT 引擎将自动推断启动核心容器所需的所有提示。未来,我们希望这些提示会减少,这得益于 GraalVM 本身的改进,或者优化方面的变化使得它们不再需要。

测试考量

代码生成需要良好的测试支持。很容易贡献无法编译的代码,或者能编译但无法达到预期结果的代码。我们一直在开发新的测试工具来帮助解决这个问题,您可以在当前私有的 spring-core-test 模块中找到它们。

简而言之,这个基础设施允许我们编译代码(通过一个抽象层,使得我们可以在内存中提供源代码),并运行断言,其中生成的代码可以轻松检索到。

假设我们为一些 Java 类生成了代码,并且入口点是 MyObject

TestCompiler.forSystem().withSources(sourceFiles)
        .compile(compiled -> {
    MyObject instance = compiled.getInstance(MyObject.class);
    // invoking + assertions
});

在我们的案例中,AOT 引擎生成一个实现 ApplicationContextInitializer 接口的入口点。这样的基础设施使我们能够执行以下操作:

  • 配置应用上下文以测试特定功能
  • 在上下文中调用 AOT 引擎
  • 使用 TestCompiler 编译我们生成的源代码
  • 创建一个新的应用上下文,并应用生成的代码,查看功能是否按预期运行

上面描述的关于生成的代码同样适用于运行时提示。我们正在开发额外的测试工具,以验证您贡献的提示与运行时行为是否匹配。但这尚未包含在此里程碑版本中,请关注 #27981 获取更多详细信息。

后续计划

在下一个里程碑版本中,我们将继续基于 Spring Native 的经验构建核心基础设施。过去在 Spring Native 中的针对特定 Spring 项目的定制将迁移到相应的项目本身,或者通过适应引擎开箱即用的支持而变得不再需要。

Spring Framework 6.0 只是第一步:我们打算在此基础上继续发展多年,这也将对 JVM 用户产生积极影响。敬请期待!

获取 Spring 时事通讯

订阅 Spring 时事通讯保持联系

订阅

抢占先机

VMware 提供培训和认证,助力您加速发展。

了解更多

获取支持

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

了解更多

即将举行的活动

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

查看全部