Spring 干掉原生 JVM?!

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 RDS MySQL Serverless,价值2615元额度,1个月
简介: Spring 干掉原生 JVM?!


Spring 团队日前发布了 Spring Native Beta 版。通过 Spring Native,Spring 应用将有机会与 GraalVM 原生镜像的方式运行。为了更好地支持原生运行,Spring Native 提供了 Maven 和 Gradle 插件,并且提供了优化原生配置的注解。

最近,Spring 发布了 Spring Native 的 beta 版本,该功能已经在 start.spring.io 上可用了。

https://github.com/spring-projects-experimental/spring-native

https://start.spring.io/

这意味着,除了 Spring 诞生以来就支持的 Java 虚拟机,官方添加了使用 GraalVM 将 Spring 应用编译成原生镜像的 beta 支持,这样的话,就能提供一种新的方式来部署 Spring 应用。Spring Native 支持 Java 和 Kotlin。

这些原生的 Spring 应用可以作为一个独立的可执行文件进行部署(不需要安装 JVM),并且还能提供有趣的特征,包括几乎瞬时的启动(一般会小于 100 毫秒)、瞬时的峰值性能以及更低的资源消耗,其代价是比 JVM 更长的构建时间和更少的运行时优化。

通过简单的 mvn spring-boot:build-image 或 gradle bootBuildImage 命令,就能生成一个优化的容器镜像,它包含了一个最小的操作系统层和一个小的原生可执行文件,该文件只包含了必需的东西即 JDK、Spring 以及应用中所使用的依赖。

请看下面这个最小的容器镜像,它是一个 50MB 的可执行文件,包含了 Spring Boot、Spring MVC、Jackson、Tomcat、JDK 和应用本身。

这种原生方式,在很多场景下都会对 Spring 应用产生价值:

  • 使用 Spring Cloud Function 的 Serverless 应用
  • 更廉价、更可持续地托管 Spring 微服务
  • 与 VMware Tanzu 这样的 Kubernetes 平台有很好的契合性
  • 想要最优的容器镜像,以打包 Spring 应用和服务

在使用场景上,比如 Piotr Mińkowski 提供了一个非常棒的指南,介绍了如何在 Knative 上使用 Spring Boot 和 GraalVM 构建原生微服务。

https://piotrminkowski.com/2021/03/05/microservices-on-knative-with-spring-boot-and-graalvm/

1. 团队协作

Spring Native beta 是整个 Spring 团队及其家族项目广泛合作的结果:Spring Framework、Spring Boot 还包括 Spring Data、Spring Security、Spring Cloud 和 Spring Initializr。

据悉,原生功能的工作范围比 Spring 更广,因为原生涉及到更广泛的 JVM 生态系统,所以官方一直在与 GraalVM 团队合作,以改善原生镜像的兼容性和资源消耗。

以下是来自 GraalVM 团队的 Vojin Jovanovic 的一段话。

“与 Spring 团队协作打造原生 JVM 生态系统是一件非常愉快的事情:他们深厚的技术知识,再加上对社区的敏感触觉,总是能带来最好的解决方案。最新的 Spring Native 版本,以及它在 JVM 生态系统中的众多用法,为原生编译的广泛采用铺平了道路。”

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

2. 支持的范围

现在,Spring Native已经从alpha过渡到beta,那么很重要的一点就是明确他弄所支持的功能范围。

Alpha是第一步,我们进行了大量试验并完善了Spring Native(以前称为Spring GraalVM Native)的体系结构,兼容性和对一系列样本进行了重大更改的封装。我们还报告了GraalVM团队修复的许多问题,目的是缩小JVM与Spring应用程序的本机之间的差距。

虽然它仍被认为是实验性的,但 beta 版意味着 Spring 现在在 Spring 生态系统的一个子集上提供了对原生的支持。如果你的应用正在使用业已支持的依赖,那么你可以试用它,在出现问题时可以提 bug 或贡献 pull request。在最新的 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 等。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

3. start.spring.io

Stéphane Nicoll 在对 http://start.spring.io 和相关 IDE 的集成中,引入了对 Spring Native 的支持,所以现在这是探索如何使用 Spring 构建原生应用最简单的方式。

添加 Spring Native 依赖后将会使用所需的依赖和插件自动配置 Maven 或 Gradle 项目,以便于支持原生。应用代码本身没有变化。

请检查自动生成的 HELP.md 文件,该文件包含了有用的链接和文档,同时它还能标记出来你是否选择了一些在原生环境下不支持的依赖。

4. 预先转换

原生与JVM有说不同:类路径在构建时是固定的,反射或资源需要进行配置,这里没有类的懒加载(可执行文件中包含的所有内容在启动的时候都会加载进来)并且有些代码可以在构建期调用。

为了充分拥抱这些特性,并且能让 Spring 应用以最大的兼容性和最小的资源消耗运行在原生环境中,Brian Clozel 在这个版本中引入了 Spring 预先(ahead-of-time,AOT)转换的 Maven 和 Gradle 插件,这个插件会对 Spring 应用执行预先转换。

第一种转换的目的是生成 GraalVM 原生配置(反射、资源、代理、原生镜像选项),这是通过由 Andy Clement 设计和实现的一个特别棒的推断引擎做到的,该引擎能够理解 Spring 编程模型和基础设施。例如,每个带有 @Controller 注解的类,都会在生成的 reflect-config.json 文件中添加一个条目。

有些原生配置是无法推断的,对于这些情况,Spring Native 引入了原生线索(native hint)注解(参见 Javadoc 以了解详情),这些注解允许 Spring Native 支持原生配置,这种方式比常规的基于 JSON 的原生镜像配置更加可维护、类型安全和灵活。例如,Spring Native 对 MySQL 驱动支持就提供了线索注解,它们会在原生镜像配置 reflect-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 原生镜像特征所引入的封闭世界(closed-world)假设,它能够自动生成针对原生环境进行优化的代码。这里的目标就是限制所需的外部原生配置的数量,从而提高兼容性,这是通过原生镜像编译器对代码结构的分析实现的,同时还能通过减少反射、资源或代理所需的配置,降低资源占用。一个具体的例子就是对各种 spring.factory(Spring Boot 背后的扩展机制)的预先转换,从而实现一个优化过的程序版本,该版本不需要反射并且会过滤掉应用上下文中不必要的条目。

对 Spring AOT来说,这只是一个开始,我们计划添加更加强大的转换,比如将 @Configuration 替换为函数式配置,从而通过预先分析替换运行时反射,能够自动生成使用像 lambda 表达式和方法引用这种程序构造的配置类。这样的话,就能允许 GraalVM 原生镜像编译器立即理解 Spring 配置,无需任何的反射配置或 *.class 资源。

需要记住的一个关键点是,在使用 Spring Native 时,这个 AOT 生成的代码在 JVM 上也会默认使用,这样的话能够通过 JVM 允许的短反馈循环(short feedback loop),用调试器和所有常规工具实现“原生友好的代码路径”。

尽管Spring AOT转换目前主要是由原生场景需求驱动,但是有很多转换并不是特定于原生场景的,有一些可能为 JVM 上运行的 Spring Boot 应用提供优化。和往常一样,对于这种主题,重要的是要以数据为驱动,所以我们会衡量效率和性能来驱动我们的决策。

我们很可能会完善 IDE 集成,目前请务必阅读相关文档,了解潜在的手动配置步骤,以便在 IDE 中运行应用程序之前更新生成的源码。

5. 结论

在支持原生方面,Spring 有两个支柱性的策略。第一个是在不需要对现有的数百万个 Spring Boot 应用进行重大改动的情况下,对 Spring 基础架构进行调整以适应原生。这包括在 Spring 顶层项目中为实现原生友好而做出的改变,像 @NativeHint 这样的基础架构,以及在 Spring Native 中逐渐成熟的 Spring AOT 构建插件。

第二个支柱比Spring本身的范围更广,原生是一个与 JVM 特性有所差异的平台,但 Java 生态系统需要尽可能地保持一致,以避免出现两种截然不同的 Java 风格,如果这样的话,将会是维护上的一个挑战。

原文链接:https://spring.io/blog/2021/03/11/announcing-spring-native-beta




相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2月前
|
Cloud Native Java Docker
【Spring云原生】Spring官宣,干掉原生JVM,推出 Spring Native!整体提升性能!Native镜像技术在Spring中的应用
【Spring云原生】Spring官宣,干掉原生JVM,推出 Spring Native!整体提升性能!Native镜像技术在Spring中的应用
|
4月前
|
JavaScript 前端开发 Java
深入探索Spring Boot的核心功能:快速构建原生程序响应式处理数据(文末送书)
深入探索Spring Boot的核心功能:快速构建原生程序响应式处理数据(文末送书)
34 0
|
5月前
|
存储 Java 测试技术
Spring 拾枝杂谈—Spring原生容器结构剖析(通俗易懂)
Spring 第一节 拾枝杂谈 分析Spring底层容器。
56 0
|
5月前
|
消息中间件 算法 Java
三面“有赞”Java岗斩获offer:Spring+JVM+并发锁+分布式+算法
年末离职,年初为面试也筹备挺长一段时间,找了不少复习资料,刷了很多题在网上投了很多简历最终面试了有赞,还有幸拿到offer!
|
5月前
|
消息中间件 前端开发 架构师
华为架构师复盘2024最全2340页面试题jvm+spring+redis+MQ+微服务
包括 Java 集合、JVM、多线程、并发编程、设计模式、Spring全家桶、Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、MongoDB、Redis、MySQL、RabbitMQ、Kafka、Linux、Netty、Tomcat、Python、HTML、CSS、Vue、React、JavaScript、Android 大数据、阿里巴巴等大厂面试题等、等技术栈!
|
7月前
|
XML Java 测试技术
JVM && 软件测试的目的和原则 && Spring基本概念 && 项目创建 && 软件测试的生命周期 && SpringBoot创建和运行 && Bean作用域
JVM && 软件测试的目的和原则 && Spring基本概念 && 项目创建 && 软件测试的生命周期 && SpringBoot创建和运行 && Bean作用域
52 0
|
9月前
|
架构师 Java 应用服务中间件
每天学四小时:Java+Spring+JVM+分布式高并发,架构师指日可待
每天花四小时学马士兵Java、大数据、Spring、Redis、Jvm、分布式、高并发、坦克大战,你会成为高级架构师 适合小白入门到高级,同时适合工作-两年的同学,因为整套课程全程通过项目演变的过程,从传统单机到整合分布式缓存,高井发负载均衡技术数据一致性方案,再到微服务,注册发现,路由熔断,统一配置管理,服务质量管理,中间件技术选型,底层原理源码分析,覆盖JAVA、spring全家桶、kafka. 多种MQ、缓存数据库技术,docker容器k8s部署,只要跟着学,不只会操作,还能领悟技术发展的因果关系让您面试先人一 步!
|
9月前
|
消息中间件 算法 Java
三面“有赞”Java岗斩获offer:Spring+JVM+并发锁+分布式+算法
年末离职,年初为面试也筹备挺长一段时间,找了不少复习资料,刷了很多题在网上投了很多简历最终面试了有赞,还有幸拿到offer!
|
2月前
|
Java 应用服务中间件 Maven
SpringBoot 项目瘦身指南
SpringBoot 项目瘦身指南
53 0
|
2月前
|
缓存 安全 Java
Spring Boot 面试题及答案整理,最新面试题
Spring Boot 面试题及答案整理,最新面试题
137 0