领先一步
VMware 提供培训和认证,助您加速进步。
了解更多熟悉 Spring Native 实验性项目的朋友们都知道,自 2019 年以来,Spring 团队一直在为 Spring 应用程序开发原生镜像支持。在 2021 年 3 月 首次发布 Beta 版 之后,我们在 2021 年 12 月对 Spring Native 的工作进行了 大规模的修订。
我们还在去年的 SpringOne 大会上宣布,我们计划在 2022 年将这项工作推广到 Spring Framework 6.0 正式版。在发布第三个里程碑版本之后,这篇博文将带您了解已包含的内容以及接下来的计划。
提前处理应用程序上下文为优化打开了许多大门。根据具体情况,我们可以减少我们分发的代码量,预先计算您在组件中声明的某些功能,从而加快启动速度,并识别在受限环境中可能出现问题的项,为它们提供替代方案。
Spring Framework 6.0.0-M3 提供了基于 Spring Native 的首批功能,并进行了扩展审查和集成到核心容器中。它不是作为新功能以附加模块的形式出现,而是深度集成到现有核心功能中。目前包括:
当典型的 Spring 应用程序运行时,应用程序上下文会调用许多后置处理器来准备 bean 工厂:解析配置类、扫描类路径以及其他最终可能触发自动配置解析的操作。一旦这些完成,在大多数情况下,它们在运行时就不再需要了。
通过定义明确的环境(类路径等),这一切都可以在构建时完成,以便只有当前环境中相关的 bean 定义被添加到 bean 工厂。在构建时运行的后置处理器将被丢弃,并替换为它们贡献的代码。
有许多方法可以“提前”贡献代码,从注解处理到字节码生成。我们选择让我们的新引擎生成 Java 源代码,并在构建过程中将其贡献给应用程序。我们相信这在开发人员体验和优化机会之间取得了恰当的平衡。
这不仅能够以熟悉且透明的方式启用原生镜像用例,而且我们还相信这将在未来为传统的 JVM 应用程序带来好处。例如,AOT 引擎完全独立于原生镜像,因此您可以在 JVM 上验证应用程序的优化版本是否正常工作。
与 JVM 不同,运行原生镜像在某些情况下需要额外的配置。例如,如果您的代码通过反射调用方法,您需要进行说明,以便在原生镜像中包含必要的代码。或者,如果您需要读取类的元数据(如核心容器通常在启动时所做的那样),您需要包含该类的字节码,这可能会导致更大的镜像文件。
AOT 引擎将自动推断启动核心容器所需的所有提示。未来我们希望这些提示能够通过 GraalVM 本身的改进,或优化方面的变化而减少,使其不再必要。
生成代码需要良好的测试故事。很容易贡献出无法编译的代码,或者即使能编译也无法产生预期结果的代码。我们一直在努力开发新的测试工具来帮助我们,您可以在当前私有的 spring-core-test 模块中找到它们。
总而言之,这个基础设施允许我们编译代码(通过一个抽象层,允许我们在内存中提供源代码),并 运行断言,其中生成的代码可以轻松检索。
假设我们已经为一些 Java 类生成了代码,并且我们的入口点是 MyObject。
TestCompiler.forSystem().withSources(sourceFiles)
.compile(compiled -> {
MyObject instance = compiled.getInstance(MyObject.class);
// invoking + assertions
});
在我们的例子中,AOT 引擎生成了一个实现 ApplicationContextInitializer 接口的入口点。这样的基础设施使我们能够做到以下几点:
TestCompiler 编译我们生成的源代码上面关于生成代码的描述同样适用于提示。我们正在开发额外的测试工具来验证您贡献的提示是否与运行时行为匹配。尽管这在本里程碑版本中未能实现,请订阅 #27981 以获取更多详细信息。
在下一个里程碑版本中,我们将继续基于 Spring Native 的经验构建核心基础设施。曾经在 Spring Native 中的特定 Spring 项目的定制将迁移到项目中,或者通过适应引擎的开箱即用功能而变得不再必要。
Spring Framework 6.0 只是一个开始:我们打算在未来几年内在此基础上继续发展,这将对 JVM 用户产生积极影响。敬请期待!