宣布 Spring Native Beta 版本!

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

今天,经过一年半的努力,我很高兴宣布推出 Spring Native 的 Beta 版本,并已在 start.spring.io 上提供!

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

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

Native Spring Boot web application starting in 38 ms

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

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

原生应用对于您的 Spring 应用程序来说,有很多适用的使用场景

  • 使用 Spring Cloud Function 的无服务器应用

  • 更经济、更可持续地托管您的 Spring 微服务

  • VMware Tanzu 等 Kubernetes 平台完美契合

  • 希望创建最佳的容器镜像来打包您的 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 生态系统提供了原生支持。如果您的项目使用了受支持的依赖项,您可以尝试一下,如果出现问题,可以提交 bug贡献拉取请求。Spring Native 将针对最新的 Spring Boot 2.x 小版本的每个补丁版本发布新版本。Spring Native 0.9.0 支持 Spring Boot 2.4.3,Spring Native 0.9.1 将支持 Spring Boot 2.4.4 等。可能会出现破坏性更改,但我们会提供迁移路径的文档。文档质量达到了新的水平:参考文档提供单页 HTMLPDF 格式,我们还发布了原生提示公共 API 的 Javadoc

start.spring.io

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

Spring Native support on start.spring.io

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

请务必检查生成的 HELP.md 文件,该文件包含有用的链接和文档,同时也会指示您是否选择了某些已知在原生环境中不受支持的依赖项。

提前转换 (AOT Transformations)

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

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

第一种转换旨在基于由出色的 Andy Clement 设计和实现的推理引擎生成 GraalVM 原生配置(反射、资源、代理、native-image 选项),该引擎理解 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 原生镜像编译器能够直接理解 Spring 配置,而无需任何反射配置或 *.class 资源。

需要记住的关键一点是,使用 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 社区所有即将到来的活动。

查看全部