终于,Spring 对 JVM 动手了
mhr18 2025-01-21 19:33 16 浏览 0 评论
Spring 在今年 3 月份推出了 Spring Native Beta 版本,我本来还想着等正式发布了再研究下,不用等了,现在我们就来尝尝鲜。
https://spring.io/blog/2021/03/11/announcing-spring-native-beta
Spring Native 简介
我们都知道,传统的 Spring 应用程序都是必须依赖于 Java 虚拟机(JVM)运行的,Spring Native 的诞生就是无需 JVM,它提供了另外一种运行和部署 Spring 应用的方式(目前只支持 Java 和 Kotlin),通过 GraalVM 将 Spring 应用程序编译成原生镜像。
Spring Native 特点
1、无需 JVM 环境, Spring Native 应用程序可以作为一个可执行文件独立部署;
2、应用即时启动,一般情况下应用启动时间 < 100ms;
3、即时的峰值性能;
4、更少的内存消耗;
Spring Native 缺点
Spring Native 应用启动那么快也是有代价的,和 JVM 应用相比:
1、构建更笨重、构建时间更长;
2、更少的运行时优化;
3、很多 Java 功能受限;
4、很多特性还很不成熟;
Spring Native 应用场景
1、Spring Cloud 无服务器化(Serverless);
2、以更廉价持久的方式运行 Spring 微服务;
3、非常适合 Kubernetes 平台,如:VMware Tanzu;
4、为 Spring 应用创建更佳的容器镜像;
Spring Native 和 JVM 的区别
1、Spring Native 构建时会进行应用程序静态分析;
2、Spring Native 构建时会移除未被使用的组件;
3、Spring Native 反射、资源、动态代理需要配置化;
4、Spring Native 构建时的 classpath 是固定不变的;
5、Spring Native 没有类延迟加载,可执行文件包含所有内容都在启动时加载到内存;
6、Spring Native 构建时会运行一些代码;
7、Spring Native 对于 Java 应用程序还存在一些局限性;
GraalVM 简介
Spring Native 的核心就是 Oracle 的黑科技: GraalVM。
GraalVM 是一个由 Oracle 开发的全栈通用虚拟机,拥有高性能、跨语言交互等逆天特性,不仅支持了 Java、Scala、Groovy、Kotlin 等基于 JVM 的语言,以及 C、C++ 等基于 LLVM 的语言,还支持其他像 JavaScript、Ruby、Python 和 R 语言等,可提高多种语言的运行速度和吞吐量。
GraalVM 有以下几个特性。
- 更加高效快速的运行代码
- 能与大多数编程语言直接交互
- 使用 Graal SDK 嵌入多语言
- 创建预编译的原生镜像
- 提供一系列工具来监视、调试和配置所有代码
具体就不介绍了,阅读我之前分享的这篇文章:Oracle 发布了一个全栈虚拟机 GraalVM
重点来看原生镜像功能:
$ javac HelloWorld.java
$ time java HelloWorld
user 0.070s
$ native-image HelloWorld
$ time ./helloworld
user 0.005s
GraalVM 可以预编译成原生镜像,从而极大提速了启动时间,并能减少 JVM 应用的内存占用。现在你知道为什么 Spring Native 启动那么快的原因了!
Spring Native 正是通过 GraalVM 提供了对传统 Spring 应用程序的轻量级运行方式,在不用修改任何传统应用程序代码的情况下,通过集成 Spring Native 项目就能轻松实现。
开始尝鲜
构建 Spring Native 应用的两种方式:
1、使用 Spring Boot Buildpacks 来生成一个包含原生可执行文件的轻量级容器;
2、使用 GraalVM native image Maven 插件来生成一个包含原生可执行文件;
本文使用第一种方式进行尝鲜!
1、环境要求
这种方式需要安装 Docker 环境:
- Linux 需要配置非 root 用户可运行
- Mac 需要配置最大内存为 8G 或以上
因为我本地已经装好了,这里不再演示了,不会的点击这里阅读参考一下,或者关注:Java技术栈,在历史文章中搜索阅读。
2、添加依赖
Spring Native 在 start.spring.io 上面已经可以开始使用了,在页面上添加一个 “Spring Native“ 依赖进去就好,如下所示:
Spring Boot:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
<relativePath/>
</parent>
Spring Native:
<dependencies>
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-native</artifactId>
<version>${spring-native.version}</version>
</dependency>
</dependencies>
注意依赖版本:
Spring Native 最新版本为:0.9.2,只支持 Spring Boot 2.4.5
3、添加 Spring AOT 插件
添加 Spring AOT 插件:
<build>
<plugins>
<plugin>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-aot-maven-plugin</artifactId>
<version>0.9.2</version>
<executions>
<execution>
<id>test-generate</id>
<goals>
<goal>test-generate</goal>
</goals>
</execution>
<execution>
<id>generate</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Spring AOT 插件执行所需的提前转换,以提升原生镜像的兼容性。
4、开启原生镜像支持
在 Spring Boot Maven 插件中增加以下配置:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<builder>paketobuildpacks/builder:tiny</builder>
<env>
<BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
</env>
</image>
</configuration>
</plugin>
5、添加 Maven 仓库支持
Spring Native 依赖和插件需要在 Spring 仓库中下载,需要添加以下配置。
<repositories>
<repository>
<id>spring-release</id>
<name>Spring release</name>
<url>https://repo.spring.io/release</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-release</id>
<name>Spring release</name>
<url>https://repo.spring.io/release</url>
</pluginRepository>
</pluginRepositories>
如果不能正常下载 Native 依赖和插件,需要检查 Maven 的 settings.xml 文件:
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>*,!spring-release</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
把 mirrorOf 值由 修改为:,!spring-release
6、添加测试接口
添加一个测试接口,原生应用启动后,方便测试下可行性。
/**
* 来源:Java技术栈
*/
@SpringBootApplication
@RestController
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
@RequestMapping("/native/hi")
@ResponseBody
public String hiNative() {
return "hi native application...";
}
}
本文所有代码已上传至:https://github.com/javastacks/spring-boot-best-practice
7、构建原生应用
Maven 插件构建命令:
mvn spring-boot:build-image
这个会创建一个 Linux 容器,使用 GraalVM 原生镜像编译器构建出原生应用程序,容器镜像默认只安装在本地。
在 IDEA 插件中运行:
配置好后开始构建:
会看到大量这样的错误,不用理会,这个会在未来移除。
最终构建完成,一个简单的 Spring Boot 应用程序,这个构建却过程花了我 4 分钟。。
8、运行原生应用
使用平常运行 Docker 镜像的方式就能运行原生应用:
docker run –rm -p 8080:8080
当然也可以在项目中编写 docker-compose.yml 文件的方式,这里不再演示,感兴趣的可以关注Java技术栈,在历史文章中搜索阅读 Docker 系列文章。
一般情况下,运行原生应用程序只需要 100 毫秒以下,而运行基于 JVM 的应用程序大概需要 15 秒左右。
事实是否如此呢,一起来看看!
我天,82 毫秒就启动了,启动确实快。
再来访问我们之前写的接口:
http://localhost:8080/native/hi
输出正常,原生应用验证完成。
另外,在 target 目录中也生成了可执行的 jar 包:
然后我们用传统 JVM 环境来运行下:
java -jar spring-boot-native-1.0.jar
启动时间:1.903 秒,虽然看起来差距不大,但原生应用启动时间(0.082 秒)也比 JVM 快了 23 倍,在不同的代码量面前可能会有较大差距的体现。
当然这只是我测试的参考时间,但可以说明的原生应用运行确实要比 JVM 快不少!
我们再来比对下包的大小
查看刚生成的 Docker 镜像:
docker image ls
查看基于 JVM 的可执行 jar 包:
Docker 镜像大小:80.7 M,而基于 JVM 运行的可执行 jar 包却只有不到 20M。
这是因为原生镜像不仅包含了应用程序中所使用到的来自 JDK、Spring 中的必须项,还包含了一个最小化的 OS 系统层,所以肯定是要比之前的要大不少。
总结
本文介绍了 Spring Native 的特点,及演示了基于 Docker 镜像的原生应用。
本文所有演示代码已上传至:
https://github.com/javastacks/spring-boot-best-practice
感兴趣的都可以 Star 下该仓库,包含了之前写的 Spring Boot 教程及示例源码。
当然除了基于 Docker 镜像,还可以使用原生镜像 Maven 插件的方式,那种方式不需要 Docker,但需要安装原生镜像编译器 GraalVM,道理是一样的,这里就不再演示了,有兴趣的可以参考:
https://docs.spring.io/spring-native/docs/current/reference/htmlsingle/#getting-started-native-image
如果有使用 Docker,那第一种肯定是更好的方式,所有的依赖都打包到一个镜像中了,避免了环境污染。
最后总结一下就是,Spring Native 可以无需 JVM 运行,构建慢、启动快、内存占用少、运行优化少,另外还有很多 Java 特性受限,比如:反射、动态代理等都需要通过提前配置化,因为 Java 是一种动态链接的语言,原生应用都要提前编译,这个像反射、动态代理这种特性就会受限。
另外,目前 Spring Native 还处于 Beta 测试版本,现阶段肯定还会存在很多问题,未来可能也还会有变更,不过我会继续关注的,后续我也会更新更多 Java 系列最新技术实战文章,Java技术栈第一时间推送。请大家持续关注哦!
本节所有内容都是参考官网最新文档,可谓是做了第一个吃螃蟹的人,觉得我的文章对你用收获的话,动动小手,给个在看、转发,原创不易,栈长需要你的鼓励。
版权申明:本文系 “Java技术栈” 原创,原创实属不易,转载、引用本文内容请注明出处,禁止抄袭、洗稿,请自重,尊重大家的劳动成果和知识产权,抄袭必究。
相关推荐
- 【预警通报】关于WebLogic存在远程代码执行高危漏洞的预警通报
-
近日,Oracle官方发布了2021年1月关键补丁更新公告CPU(CriticalPatchUpdate),共修复了包括CVE-2021-2109(WeblogicServer远程代码执行漏洞)...
- 医院信息系统突发应急演练记录(医院信息化应急演练)
-
信息系统突发事件应急预案演练记录演练内容信息系统突发事件应急预案演练参与人员信息科参与科室:全院各部门日期xxxx-xx-xx时间20:00至24:00地点信息科记录:xxx1、...
- 一文掌握怎么利用Shell+Python实现完美版的多数据源备份程序
-
简介:在当今数字化时代,无论是企业还是个人,数据的安全性和业务的连续性都是至关重要的。数据一旦丢失,可能会造成无法估量的损失。因此,如何有效地对分布在不同位置的数据进行备份,尤其是异地备份,成为了一个...
- docker搭建系统环境(docker搭建centos)
-
Docker安装(CentOS7)1.卸载旧版Docker#检查已安装版本yumlistinstalled|grepdocker#卸载旧版本yumremove-ydocker.x...
- 基础篇:数据库 SQL 入门教程(sql数据库入门书籍推荐)
-
SQL介绍什么是SQLSQL指结构化查询语言,是用于访问和处理数据库的标准的计算机语言。它使我们有能力访问数据库,可与多种数据库程序协同工作,如MSAccess、DB2、Informix、M...
- Java21杀手级新特性!3行代码性能翻倍
-
导语某券商系统用这招,交易延迟从12ms降到0.8ms!本文揭秘Oracle官方未公开的Record模式匹配+虚拟线程深度优化+向量API神操作,代码量直降70%!一、Record模式匹配(代码量↓8...
- 一文读懂JDK21的虚拟线程(java虚拟线程)
-
概述JDK21已于2023年9月19日发布,作为Oracle标准Java实现的一个LTS版本发布,发布了15想新特性,其中虚拟线程呼声较高。虚拟线程是JDK21中引入的一项重要特性,它是一种轻量级的...
- 效率!MacOS下超级好用的Linux虚拟工具:Lima
-
对于MacOS用户来说,搭建Linux虚拟环境一直是件让人头疼的事。无论是VirtualBox还是商业的VMware,都显得过于笨重且配置复杂。今天,我们要介绍一个轻巧方便的纯命令行Linux虚拟工具...
- 所谓SaaS(所谓三维目标一般都应包括)
-
2010年前后,一个科技媒体的主编写一些关于云计算的概念性问题,就可以作为头版头条了。那时候的云计算,更多的还停留在一些概念性的问题上。而基于云计算而生的SaaS更是“养在深闺人未识”,一度成为被IT...
- ORA-00600 「25027」 「x」报错(报错0xc0000001)
-
问题现象:在用到LOB大对象的业务中,进行数据的插入,失败了,在报警文件中报错:ORA-00600:内部错误代码,参数:[25027],[10],[0],[],[],[],[],[...
- 安卓7源码编译(安卓源码编译环境lunch失败,uname命令找不到)
-
前面已经下载好源码了,接下来是下载手机对应的二进制驱动执行编译源码命令下载厂商驱动https://developers.google.com/android/drivers?hl=zh-cn搜索NGI...
- 编译安卓源码(编译安卓源码 电脑配置)
-
前面已经下载好源码了,接下来是下载手机对应的二进制驱动执行编译源码命令下载厂商驱动https://developers.google.com/android/drivers?hl=zh-cn搜索NGI...
- 360 Vulcan Team首战告捷 以17.5万美金强势领跑2019“天府杯“
-
2019年11月16日,由360集团、百度、腾讯、阿里巴巴、清华大学与中科院等多家企业和研究机构在成都联合主办了2019“天府杯”国际网络安全大赛暨2019天府国际网络安全高峰论坛。而开幕当日最激荡人...
- Syslog 日志分析与异常检测技巧(syslog发送日志配置)
-
系统日志包含有助于分析网络设备整体运行状况的重要信息。然而,理解并从中提取有效数据往往颇具挑战。本文将详解从基础命令行工具到专业日志管理软件的全流程分析技巧,助你高效挖掘Syslog日志价值。Gr...
- 从Oracle演进看数据库技术的发展(从oracle演进看数据库技术的发展的过程)
-
数据库技术发展本质上是应用需求驱动与基础架构演进的双向奔赴,如何分析其技术发展的脉络和方向?考虑到oracle数据库仍然是这个领域的王者,以其为例,管中窥豹,对其从Oracle8i到23ai版本的核...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle位图索引 (74)
- oracle基目录 (50)
- oracle批量插入数据 (65)
- oracle事务隔离级别 (53)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)