宣布 Spring Native Beta 版!

工程 | Sébastien Deleuze | 2021年3月11日 | ...

今天,经过一年半的努力,我很高兴地宣布,我们发布了Spring Native 的 Beta 版本,并且它已在 start.spring.io 上可用!

实际上,这意味着除了自 Spring 诞生以来一直支持的常规 Java 虚拟机之外,我们还增加了对使用 GraalVM 将 Spring 应用程序编译为 原生镜像 的 Beta 支持,以便提供一种部署 Spring 应用程序的新方法。支持 Java 和 Kotlin。

这些原生 Spring 应用程序可以作为独立的可执行文件部署(无需安装 JVM),并提供一些有趣的特性,包括几乎即时的启动(通常 < 100ms)、即时的峰值性能和更低的内存消耗,但代价是构建时间更长,运行时优化比 JVM 少。

Native Spring Boot web application starting in 38 ms

使用简单的 mvn spring-boot:build-imagegradle bootBuildImage 命令,您可以生成一个优化的容器镜像,其中包含最小的操作系统层和一个小的原生可执行文件,该文件仅包含 JDK、Spring 和应用程序中使用的依赖项所需的位。例如,下面是一个包含 Spring Boot、Spring MVC、Jackson、Tomcat、JDK 和应用程序的 50MB 可执行文件的最小容器镜像。

Minimal container image with a 50MB executable containing: Spring Boot

在许多情况下,原生镜像可能对您的 Spring 应用程序有意义

  • 使用 Spring Cloud Function 实现无服务器

  • 更便宜、更可持续地托管您的 Spring 微服务

  • 非常适合 Kubernetes 平台,例如 VMware Tanzu

  • 想要创建优化的容器镜像来打包您的 Spring 应用程序和服务

我相信优秀的 Spring 社区会发现更多用例,例如 Piotr Mińkowski 关于如何使用 Spring Boot 和 GraalVM 在 Knative 上构建原生微服务的 这篇优秀的教程

团队协作

Spring Native Beta 版是 Spring 团队及其项目组合(Spring Framework、Spring Boot 以及 Spring Data、Spring Security、Spring Cloud 和 Spring Initializr)广泛合作的结果。观看此视频,了解 Spring 团队如何构建 Spring Native Beta 版及其提供的功能,包括全新 start.spring.io 支持的演示。

我们的原生工作范围比 Spring 更广,因为原生涉及更广泛的 JVM 生态系统,因此我们一直在与 GraalVM 团队合作,以提高原生镜像的兼容性和占用空间。以下是来自 GraalVM 团队的 Vojin Jovanovic 的引言:

“与 Spring 团队合作构建原生 JVM 生态系统是一件非常令人高兴的事情:他们深厚的技术知识,加上对社区的细致关怀,总是能带来最佳的解决方案。最新的 Spring Native 版本及其在 JVM 生态系统中的众多应用,为原生编译的广泛采用铺平了道路。”

支持范围

随着 Spring Native 从 Alpha 版升级到 Beta 版,我认为明确我们提供的支持范围非常重要。

Alpha 版是第一步,我们进行了大量的实验,并对 Spring Native(以前称为 Spring GraalVM Native)的架构、兼容性和在一组示例上的占用空间进行了改进,其中有很多重大更改。我们还报告了 许多问题,GraalVM 团队已修复这些问题,以减少 Spring 应用程序的 JVM 和原生之间的差距。

虽然它仍然被认为是实验性的,但 Beta 版意味着 Spring 现在提供了 对 Spring 生态系统子集的原生支持。如果您正在使用受支持的依赖项,可以在您的项目上尝试它,并在出现问题时 提交错误报告贡献拉取请求。对于最新 Spring Boot 2.x 次要版本的每个补丁版本,都会发布一个新的 Spring Native 版本。Spring Native 0.9.0 支持 Spring Boot 2.4.3,Spring Native 0.9.1 将支持 Spring Boot 2.4.4,等等。将会发生重大更改,但我们会记录迁移路径。文档质量达到了一个新的水平:参考文档可作为 html 单页pdf 获取,我们还发布了 原生提示公共 API 的 Javadoc

start.spring.io

Stéphane Nicoll 已在 start.spring.io 和相关的 IDE 集成中引入了对 Spring Native 的支持,因此,从今天起,这可能是探索如何使用 Spring 构建原生应用程序的最简单方法。

Spring Native support on start.spring.io

添加 Spring Native 依赖项将自动使用所需的依赖项和插件配置您的 Maven 或 Gradle 项目以支持原生。应用程序代码本身保持不变。

请务必检查生成的 HELP.md 文件,其中包含有用的链接和文档,但也指示您是否选择了一些在原生环境中尚不支持的依赖项。

提前转换

原生与 JVM 不同:类路径在构建时固定,需要进行反射或资源配置,例如没有类延迟加载(可执行文件中包含的所有内容都在启动时加载到内存中),并且可以在构建时调用一些代码。

为了充分利用这些特性并允许 Spring 应用程序在原生环境中以最大的兼容性和最小的占用空间运行,Brian Clozel 在此版本中引入了 Spring 提前 (AOT) Maven 和 Gradle 插件,这些插件对您的应用程序执行提前转换。

第一种转换旨在基于由优秀的 Andy Clement 设计和实现的推理引擎生成 GraalVM 原生配置(反射、资源、代理、原生镜像选项),该引擎了解 Spring 编程模型和基础结构。例如,对于每个用 @Controller 注解的类,都会将一个条目添加到生成的 reflect-config.json 文件中。

某些原生配置无法推断,对于这些情况,我们正在引入 原生提示注解(有关更多详细信息,请参阅 Javadoc),这允许 Spring Native 以比常规基于 JSON 的原生镜像配置更易于维护、类型安全和灵活的方式支持原生配置。例如,Spring Native 中的 MySQL 驱动程序支持提供以下提示,这些提示将允许生成原生镜像 reflect-config.jsonresource-config.jsonnative-image.properties 中的正确条目:

@NativeHint(
    trigger = Driver.class,
    options = "--enable-all-security-services",
    types = @TypeHint(types = {
       FailoverConnectionUrl.class,
       FailoverDnsSrvConnectionUrl.class,
       // ...
    }), resources = {
	@ResourceHint(patterns = "com/mysql/cj/TlsSettings.properties"),
	@ResourceHint(patterns = "com.mysql.cj.LocalizedErrorMessages",
                      isBundle = true)
})
public class MySqlHints implements NativeConfiguration {}

NativeConfiguration 和其他 动态配置机制 允许更强大和动态的配置生成,但请注意,它们的 API 将在即将发布的版本中发生很大变化。

Spring 开发者也可以直接使用特定于应用程序的原生提示注释他们的@Configuration@SpringBootApplication 类,例如,通过RestTemplateWebClient 等编程 API 将Book 类序列化为 JSON。

@TypeHint(types = Book.class)
@SpringBootApplication
public class WebClientApplication {
    // ...
}

在使用提前转换系统时,最后也是可能最强大的机制是能够使用 Spring Boot 部署模型引入的封闭世界假设结合 GraalVM 原生镜像特性自动生成原生优化的代码(源代码和字节码)。这里的目标是通过使用原生镜像编译器可以开箱即用地分析的代码结构来减少所需的额外原生配置数量以提高兼容性,并通过减少反射、资源或代理所需的配置数量来降低占用空间。一个具体的例子是将各种spring.factories(Spring Boot 背后的扩展机制)提前转换为优化的编程版本,该版本不需要反射,并且可以过滤掉应用程序上下文中的不必要条目。

这只是 Spring AOT 的开始,我们打算添加更强大的转换,例如@Configuration转换为函数式配置,以通过提前分析来替换运行时反射,该分析将自动生成使用 lambda 表达式和方法引用的编程结构的配置类。这将允许 GraalVM 原生镜像编译器无需任何反射配置或*.class资源即可开箱即用地理解 Spring 配置。

需要注意的关键一点是,当使用 Spring Native 时,此 AOT 生成的代码在 JVM 上也默认使用,以便您可以使用 JVM 允许的短反馈循环、调试器和所有常规工具来使用“原生友好型代码路径”。

虽然 Spring AOT 转换目前主要由原生需求驱动,但其中很多都不是特定于原生的,并且某些转换可能为在 JVM 上运行 Spring Boot 应用程序提供优化。像这类主题一样,重要的是要数据驱动,因此我们将衡量效率和性能以指导我们的决策。

我们可能会改进 IDE 集成,目前请确保阅读相关文档,了解在 IDE 中运行应用程序之前可能需要的手动配置步骤以更新生成的源代码。

结论

Spring 成为原生的策略有两个主要支柱。第一个是使 Spring 基础架构适应原生环境,而无需对数百万个现有的 Spring Boot 应用程序进行重大更改。这包括我们在 Spring 顶级项目中进行的更改,以使其对原生环境友好,以及我们在 Spring Native 中不断完善的@NativeHint 和 Spring AOT 构建插件等基础架构。查看我们的路线图,了解有关即将采取的步骤的更多信息。

第二个支柱比 Spring 本身更广泛,原生是一个与 JVM 不同的平台,但 Java 生态系统需要尽可能保持一致,以避免出现两种截然不同的 Java 版本,这将难以维护。这就是为什么我们与 GraalVM 团队紧密合作以缩小差距的原因。在接下来的几个月里,此次合作将重点放在改进更广泛的 JVM 生态系统的原生测试和原生配置。

Spring 开发者可以通过我们提供的各种示例了解更多关于原生的信息,访问start.spring.io测试我们新的原生支持,阅读更新的参考指南,阅读发行说明(尤其是如果您要从以前的版本升级),甚至贡献您最喜欢的依赖项的支持。如果您想了解有关相关 Spring 商业支持的更多信息,也可以联系我们

最后,我要衷心感谢 Spring 社区已经提供的许多有用的反馈和贡献,感谢 GraalVM 团队的精彩合作,以及辛勤工作以使 Spring 开发者更容易采用原生的更广泛的 Spring 团队。

祝您愉快!

获取 Spring 新闻

关注 Spring 新闻

订阅

领先一步

VMware 提供培训和认证,以加快您的进步。

了解更多

获得支持

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

了解更多

即将举行的活动

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

查看全部