经过一年半的工作,我很高兴地宣布,Spring Native beta 版发布,并且可在 start.spring.io 中直接使用!
这意味着 Spring 除了支持的常规 Java 虚拟机外部署外,我们还增加了使用 GraalVM 将 Spring 应用程序编译为 Native images 的方式,用来对编译型的 Spring 应用程序提供 bata 版支持。同时也支持 Java 和 Kotlin。
这些 Native Spring 应用程序可以作为独立可执行文件进行部署(无需安装 JVM),并且还提供了一些有趣的特性,包括几乎即时启动(通常<100ms)、即时峰值性能和较低的内存消耗,但同时也会付出一些代价,比如构建的时间更长,运行时优化比 JVM 更少。
图片
使用 mvn spring-boot:build-image
或 gradle bootBuildImage
命令,就可以生成一个优化过的容器镜像,该镜像将包含最小的操作系统层和一个小的可执行文件,该文件只提供 JDK、Spring 和应用程序中使用的依赖所需的 bits。例如,下面一个最小的容器镜像,其中包含一个 50MB 的可执行文件,其中包含 Spring Boot、Spring MVC、Jackson、Tomcat、JDK 和应用程序。
图片
在广泛的使用案例中,Native 原生使您的 Spring 应用程序更有意义:
我相信在 Spring 社区您会发现更多有趣的示例,像 this great tutorial 这个开源项目就是演示如何在 Knative 上使用 Spring Boot 和 GraalVM 构建 Native 微服务。
Spring Native beta 版本是 Spring 团队和 Spring 生态深度协作的产物:Spring Framework、Spring Boot 以及 Spring Data、Spring Security、Spring Cloud 和 Spring Initializr。通过下面这个视频来观看 Spring 团队介绍我们该如何构建 Spring Native beta 及其它所提供的功能,包括对于全新的 start.spring.io 支持的演示。
我们的 Native 工作范围比 Spring 更广,因为 Native 涉及更广泛的 JVM 生态,所以我们一直在与 GraalVM 团队合作,优化 Native image 的兼容性和空间占用。这里是 GraalVM 团队成员 Vojin Jovanovic 的一段话:
“与 Spring 团队合作构建 native JVM 生态是一件非常愉快的事:他们深厚的技术知识和敏锐社区洞察总能带来最佳的解决方案。最新的 Spring Native 版本以及 Spring 在 JVM 生态中的大量使用,为 native 编译的广泛使用铺平了道路。”
随着 Spring Native 从 alpha 过渡到 beta 版,弄清支持范围非常重要。
Alpha 是第一步,我们进行了大量实验并完善了 Spring Native(以前称为 Spring GraalVM Native)体系结构、兼容性和对一系列示例进行了大量的更改。我们还反馈了 GraalVM 团队为了缩小 JVM 和 Native for Spring 应用之间的差距而修复的许多问题。
尽管它仍被认为是试验性的,但 beta 意味着 Spring 现在为 Spring 生态的子集提供了对 Native 的支持。如果您的项目正在使用可支持的依赖,可以在项目上试用它;如果出现问题,请报告 bug或发起 pr 请求。最新版本的 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 的形式提供,并且我们发布了 Native hint 公共 Api 的 Javadoc。
Stéphane Nicoll(Spring 核心开发者之一)添加了 start.spring.io 对 Spring Native 的支持和相关 IDE 的集成,到目前为止,这是探索如何使用 SpringNative 应用程序最简单快速的方法。
图片
添加 Spring Native 依赖项将自动配置 Maven 或 Gradle,其中包含支持 Native 所需的依赖项和插件。应用程序本身代码是不需要更改的。
请务必检查生成的 HELP.md
文件,其中包含常用的链接和文档,另外还特别标准了 Native 无法支持的某些依赖。
Native 与 JVM 不同之处:classpath 在构建时是固定的,反射或资源需要配置,没有类延迟加载(可执行文件中的所有内容都在启动时加载到内存中),一些代码可以在构建时被调用。
为了充分利用这些特性,并允许 Spring 应用程序在 Native 上以最大的兼容性和最小的占用空间运行,Brian Clozel在这个发布版中引入了 Spring ahead-of-time (AOT)Maven 和 Gradle 插件,它们可以在应用程序上执行提前转换。
第一种转换是基于著名的 Andy Clement 设计和实现的推理引擎来生成 GraalVM Native 配置(反射、资源、代理、本机映像选项),Andy Clement 了解 Spring 编程模型和基本构造是什么样的。例如,对于@Controller
注解的每一个类,都有一个条目被添加到已生成的reflect-config.json
文件中。
一些 Native 配置无法被推理出来,针对这个问题,我们引入了 Native hint annotations(更多细节请参考Javadoc),它允许 Spring Native 使用一种比常规 JSONnative image 配置更易于维护、类型安全和更加灵活的方式支持 native 配置。
例如,MySQL 驱动程序支持 Spring Native 提供提示,允许在 Native imagereflect-config.json
,resource-config.json
和native-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
,例如通过 RestTemplate 或 WebClient 之类的 API 将Book
类序列化为 JSON:
@TypeHint(types = Book.class)
@SpringBootApplication
public class WebClientApplication {
// ...
}
在使用预转换机制时,最后一种可能也是最强大的机制是使用 Spring Boot 部署模型引入的封闭假设和 GraalVM Native image 特性自动生成 Native 优化的代码(源代码和字节码)的能力。这里的目标是限制所需额外的 Native 配置的数量来增加兼容性,通过使用代码结构可以解析出开箱即用的 Native image,并且通过减少反射,资源或代理所需的配置量实现更低的空间占用。这方面一个具体的示例是将各种spring.factories
(Spring Boot 背后的扩展机制)提前转换为优化的编程版本,该版本不需要反射,并且可以在应用程序的上下文中过滤掉不必要的条目。
这只是 Spring AOT 的一个开始,我们打算在功能配置中添加更强大的转换(如@Configuration),以使用预解析来替换运行时反射,该预解析将自动生成将使用 lambdas 和 method 这样的程序化构造的配置类。这将允许 GraalVM 本机映像编译器能开箱即用的推断 Spring 配置,而不需要任何反射配置或*.class
资源。
关键是在使用 Spring Native 时,默认情况下在 JVM 上也会使用 AOT 生成的代码,以允许您使用 JVM 允许的短反馈循环来使用“Native 友好的代码路径”。
虽然 Spring AOT 转换目前主要是由 Native 需求驱动的,但其中很多都不是 Native 特定的,有些可能会为在 JVM 上运行 Spring Boot 应用程序提供优化。跟以往一样,重要的是数据驱动,因此我们将权衡效率和性能来驱动我们的决策。
我们也会完善 IDE 的集成,确保在 IDE 中运行应用程序之前,请先阅读相关文档以了解的手动配置步骤,更新生成的源代码。
Spring 转向 Native 的战略有两个主要侧重点。第一个是使 Spring 基础架构适配 Native,而不需要对数百万个现有的 Spring Boot 应用程序进行重大修改。其中包括我们在 Spring 顶级项目中所做的更改,使其对 Native 友好,我们将在 Spring Native 中发展像@NativeHint
之类的基础架构以及 Spring AOT 构建插件。查看我们的路线规划,以获取更多关于后续进展的信息。
第二个是比 Spring 本身更广泛,Native 是一个具有与 JVM 不同的特性的平台,但是 Java 生态系统需要尽可能地保持一致,以免出现两种非常不同的 Java 风格,这将导致难以维护。这就是为什么我们与 GraalVM 团队进行紧密合作以缩小这一差距的原因。在接下来的几个月中,我们将专注于在更广泛的 JVM 生态系统改善提升 Native 的测试和配置。
Spring 开发者们可以通过我们提供的各种示例来了解有关 Native 的更多信息,继续进行start.spring.io来测试我们新 Native 的支持,阅读更新的参考指南,阅读发行说明,尤其是从早期版本升级,甚至为您最喜欢的依赖提供支持。如果您想了解更多有关 Spring 商业化的支持信息,也可以与我们联系。
最后,我非常感谢 Spring 社区提供了许多有用反馈和贡献,感谢 GraalVM 团队有如此出色的协作,以及更多的 Spring 开发者团队,是他们的努力使 Native 集成变得更加容易。
Enjoy!
译者校对:xkcoding、如梦技术、吴天狗、JustAuth 亚东、PIG 冷冷、老叶
原文链接:https://spring.io/blog/2021/03/11/announcing-spring-native-beta
Spring Navite 文档:https://docs.spring.io/spring-native/docs/current/reference/htmlsingle