当前位置: 首页 > news >正文

Spring Native 解放 JVM

一、Spring Native 是什么

Spring Native可以通过GraalVMSpring应用程序编译成原生镜像,提供了一种新的方式来部署Spring应用。与Java虚拟机相比,原生镜像可以在许多场景下降低工作负载,包括微服务,函数式服务,非常适合容器和Kubernetes。使用原生镜像有明显优势,如快速启动,提高峰值性能以及降低内存消耗。Spring Native支持JavaKotlin

这个项目的目标是寻找Spring JVM的替代方案,提供一个能将应用程序打包,并运行在轻量级容器的方案。期望能够在Spring Native中支持所有的Spring应用程序(几乎不用修改代码)。

原生(本地)镜像是一种将Java代码构建为独立可执行文件的技术。该可执行文件包括应用程序类、其依赖项的类、运行时库类以及来自JDK的静态链接本地代码。JVM被打包到原生镜像中,因此在目标系统上不需要任何Java运行环境,但构建产物依赖于平台。因此,需要为每个支持的目标系统进行一次构建,在使用Docker等容器技术时会更加简单,将容器构建为一个目标系统,可以部署到任何Docker运行时。

二、优点

Spring Native的基础是GraalVM,而GraalVM是使用Java静态编译,将Java字节码编译为汇编代码,即二进制native程序,他摒弃了JVM,这是成就它所有优点的根本原因。
【1】编译出来的原生Spring应用可以作为一个独立的可执行文件进行部署(不需要安装JVM
【2】几乎瞬时的启动(一般小于100毫秒)
【3】瞬时的峰值性能
【4】更低的资源消耗

三、局限性

GraalVM项目也有一些缺点和权衡,希望随着时间的推移有所改进:
【1】构建本地映像是一个繁重的过程,比JVM更长的构建时间;
【2】相比于传统的Java运行方式,运行时优化不足;
【3】不能直接支持反射、动态代理等动态特性;
【4】现在处于实验阶段,生态比较少;

四、原生镜像(native image)和常规 JVM 程序的区别

【1】在构建时会从主入口点对应用程序进行静态分析。
【2】在构建时会移除未使用的代码。
【3】需要配置反射、动态代理等。
【4】类路径ClassPath在构建时就已经确定。
【5】没有类延迟加载:可执行文件中所有的内容都会在启动时加载到内存中。
【6】在构建时就运行了一些代码。
【7】构建原生镜像还存在一些局限性。
【8】一些Java切面类的特性未得到完全支持。

五、前置条件:GraalVM

通用递归应用和算法语言虚拟机Graal VM是一个高性能的JDK发行版,专为Java和其他JVM语言编写,同时支持JavaScriptRubyPython和其他几种语言。GraalVM的多语言能力使得在一个应用程序中混合使用多种编程语言成为可能,同时消除了不同语言间互相调用的成本。它提供了一个原生镜像生成器Native Image builder,这是一个从Java应用中生成原生代码并将其与VM一起打包成独立可执行文件的工具。Spring Boot MavenGradle Plugin除了少数 例外情况(Mockito目前不支持原生测试),正式支持该工具。

Ahead-Of-Time(AOT)编译是将高级Java代码编译成本地可执行代码的过程。通常由JVM的即时编译器JIT在运行时进行编译,这样可以在执行应用程序时进行观察和优化。在AOT编译的情况下,这一优势就不复存在了。

通常,在进行AOT(Ahead-of-Time)编译之前,可以选择进行一个单独的步骤,称为AOT处理,即从代码中收集元数据并提供给AOT编译器。将这两个步骤分开是有意义的,因为AOT处理可以是针对特定框架的,而AOT编译器更加通用。下面的图片给出了一个概览:

Java平台的另一个特点是,只需将JAR放入类路径,就能在目标系统上进行扩展。通过启动时的反射和注解扫描,就能在应用中获得扩展行为。不幸的是,这会减慢启动时间,而且不会带来任何好处,尤其是对于云原生应用,因为在云原生应用中,服务器运行时和Java基类都打包到了JAR中。因此,可以放弃这一功能,然后可以使用闭环优化Closed World Optimization来构建应用。

详细信息参考:JIT即时编译与AOT提前编译; GraalVM :官网

六、Spring Native 基础环境搭建

【1】必须安装Docker 可以参考 Windows10 Docker Desktop安装 ,同时注意要能够以非root用户启动和运行。可以通过使用docker run hello-world (不包含sudo)命令检查Docker daemon是否可用。
【2】快速创建一个SpringBoot项目
【3】添加Spring Native依赖: 必须在项目中手动加入和配置。对于AOT处理,有一个单独的MavenGradle插件,它并没有合并到Spring Boot插件中。org.springframework.experimental:spring-native提供了native配置的API,例如@NativeHint这些Spring运行成native image的注解类。

<dependency><groupId>org.springframework.experimental</groupId><artifactId>spring-native</artifactId><version>0.9.1</version>
</dependency>

【4】添加Spring AOT插件: Spring AOT插件执行代码的提前转换,有助于改善原生镜像的占用空间和修复native image的兼容性。

<plugin><groupId>org.springframework.experimental</groupId><artifactId>spring-aot-maven-plugin</artifactId><version>0.9.1</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>

【5】开启native image支持: Spring BootSpring Boot Buildpacks support可以将Spring Boot应用程序打包成一个容器。native image buildpack可以通过BP_NATIVE_IMAGE环境变量开启。

<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>

【6】构建本地应用程序: 通过此命令,可以创建一个使用GraalVM native image compiler构建的Linux容器,默认情况下,这个镜像是在本地。

mvn spring-boot:build-image

【7】原生镜像构建:Profile将在打包阶段调用构建中的native-image编译器。通过在Maven package命令中提供native Profile,就可以构建原生镜像了:mvn clean package -Pnative

<profiles><profile><id>native</id><build><plugins><plugin><groupId>org.graalvm.buildtools</groupId><artifactId>native-maven-plugin</artifactId><version>0.9.17</version><executions><execution><id>build-native</id><goals><goal>build</goal></goals><phase>package</phase></execution></executions></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><classifier>exec</classifier></configuration></plugin></plugins></build></profile>
</profiles>

相关文章:

  • Django视图
  • 人工智能|深度学习——基于全局注意力的改进YOLOv7-AC的水下场景目标检测系统
  • Duilib 的WinMain函数学习
  • SQL世界之函数+语句(九,十)
  • Spring Cloud Ribbon:负载均衡
  • HarmonyOS鸿蒙学习基础篇 - 自定义组件(一)
  • MongoDB聚合操作符:$accumulator
  • ELAdmin 隐藏添加编辑按钮
  • C语言求解猴子分桃子
  • Django学习笔记教程全解析:初步学习Django模型,初识API,以及Django的后台管理系统(Django全解析,保姆级教程)
  • 深度学习领域的最新前沿:2024年的关键突破与趋势
  • 应急响应实战笔记02日志分析篇(3)
  • [BIZ] - 1.金融交易系统特点
  • 公需课考试怎么搜题找答案? #学习方法#学习方法
  • redis中key到了过期时间怎么删除
  • hexo+github搭建个人博客
  • 002-读书笔记-JavaScript高级程序设计 在HTML中使用JavaScript
  • Android组件 - 收藏集 - 掘金
  • Centos6.8 使用rpm安装mysql5.7
  • ES6, React, Redux, Webpack写的一个爬 GitHub 的网页
  • PHP 小技巧
  • Vim Clutch | 面向脚踏板编程……
  • 半理解系列--Promise的进化史
  • 对超线程几个不同角度的解释
  • 多线程 start 和 run 方法到底有什么区别?
  • 工作踩坑系列——https访问遇到“已阻止载入混合活动内容”
  • 关于Java中分层中遇到的一些问题
  • 聊聊flink的BlobWriter
  • 三栏布局总结
  • 移动端解决方案学习记录
  • kubernetes资源对象--ingress
  • ​Linux Ubuntu环境下使用docker构建spark运行环境(超级详细)
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • # 睡眠3秒_床上这样睡觉的人,睡眠质量多半不好
  • #pragma预处理命令
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第2节(共同的基类)
  • (Redis使用系列) Springboot 使用redis实现接口Api限流 十
  • (二)c52学习之旅-简单了解单片机
  • (非本人原创)我们工作到底是为了什么?​——HP大中华区总裁孙振耀退休感言(r4笔记第60天)...
  • (附源码)spring boot建达集团公司平台 毕业设计 141538
  • (附源码)计算机毕业设计ssm本地美食推荐平台
  • (四)鸿鹄云架构一服务注册中心
  • (详细版)Vary: Scaling up the Vision Vocabulary for Large Vision-Language Models
  • (一)使用Mybatis实现在student数据库中插入一个学生信息
  • (译)2019年前端性能优化清单 — 下篇
  • (转)大型网站架构演变和知识体系
  • (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】...
  • .net core 6 使用注解自动注入实例,无需构造注入 autowrite4net
  • .net 怎么循环得到数组里的值_关于js数组
  • .NET国产化改造探索(一)、VMware安装银河麒麟
  • .NET性能优化(文摘)
  • [ vulhub漏洞复现篇 ] struts2远程代码执行漏洞 S2-005 (CVE-2010-1870)
  • [AI]文心一言出圈的同时,NLP处理下的ChatGPT-4.5最新资讯
  • [Angularjs]asp.net mvc+angularjs+web api单页应用之CRUD操作
  • [C#]C#学习笔记-CIL和动态程序集