Spring 6.0 新特性

文章目录

  • Spring的发展历史
  • AOT
  • GraalVM
  • SpringBoot实战AOT
  • RuntimeHints
    • 案例分析
    • RuntimeHintsRegistrar
  • SpringBoot中AOT核心代码

Spring的发展历史

image.png

AOT

Spring 6.0的新特性Ahead of Time(AOT)编译是一种技术,可以提前将Spring应用程序编译成原生镜像,从而加快启动速度并降低内存消耗。AOT编译与传统的即时编译(JIT)相比,最大的优点是可以在程序运行前进行预编译,避免在程序运行时进行编译和内存消耗。

JIT(Just-in-time) 动态编译,即时编译,也就是边运行边编译,在程序运行时,动态生成代码,启动比较慢,编译时需要占用运行时的资源。

AOT,Ahead Of Time 指的是运行前编译,预先编译,AOT 编译能直接将源代码转化为机器码,内存占用低,启动速度快,可以无需 runtime 运行,直接将 runtime 静态链接至最终的程序中,但是无运行时性能加成,不能根据程序运行情况做进一步的优化,AOT 缺点就是在程序运行前编译会使程序安装的时间增加。

简单来讲:JIT即时编译的是在程序的运行过程中,将字节码转换为可在硬件上直接运行的机器码,并部署至托管环境中的过程。而 AOT 编译指的则是,在程序运行之前,便将字节码转换为机器码的过程。

GraalVM

Spring6 支持的 AOT 技术,GraalVM 就是底层的支持,Spring 也对 GraalVM 本机映像提供了一流的支持。GraalVM 是一种高性能 JDK,旨在加速用 Java 和其他 JVM 语言编写的应用程序的执行,同时还为 JavaScript、Python 和许多其他流行语言提供运行时。 GraalVM 提供两种运行 Java 应用程序的方法:在 HotSpot JVM 上使用 Graal 即时 (JIT) 编译器或作为提前 (AOT) 编译的本机可执行文件。 GraalVM 的多语言能力使得在单个应用程序中混合多种编程语言成为可能,同时消除了外语调用成本。GraalVM 向 HotSpot Java 虚拟机添加了一个用 Java 编写的高级即时 (JIT) 优化编译器。

GraalVM 具有以下特性:

  1. 一种高级优化编译器,它生成更快、更精简的代码,需要更少的计算资源
  2. AOT 本机图像编译提前将 Java 应用程序编译为本机二进制文件,立即启动,无需预热即可实现最高性能
  3. Polyglot 编程在单个应用程序中利用流行语言的最佳功能和库,无需额外开销
  4. 高级工具在 Java 和多种语言中调试、监视、分析和优化资源消耗

SpringBoot实战AOT

在SpringBoot项目中通过AOT来提前编译我们的项目。

新建一个Maven项目。添加相关的依赖

    <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.0.2</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies>

添加相关的SpringBoot插件

    <build><plugins><plugin><groupId>org.graalvm.buildtools</groupId><artifactId>native-maven-plugin</artifactId></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>

编写一点简单的代码测试,打开 x64 Native Tools Command Prompt for VS 2019 ,切换到工程目录下

image.png

执行 mvn -Pnative native:compile 进行编译,编译成功就会在target目录下生成 EXE 文件,后续执行该文件就可以。

image.png
双击执行exe文件,会发现速度快很多

RuntimeHints

与常规 JVM 运行时相比,将应用程序作为本机映像运行需要额外的信息。例如,GraalVM 需要提前知道组件是否使用反射。同样,除非明确指定,否则类路径资源不会在本机映像中提供。因此,如果应用程序需要加载资源,则必须从相应的 GraalVM 原生图像配置文件中引用它。

APIRuntimeHints在运行时收集反射、资源加载、序列化和 JDK 代理的需求。

案例分析

声明个普通的实体类型

public class UserEntity {public String hello(){return "hello ...";}
}

在控制器中通过反射来操作处理

    @GetMapping("/hello")public String hello(){String res = "hello";try {Method hello = UserEntity.class.getMethod("hello");res =  (String)hello.invoke(UserEntity.class.newInstance(),null);} catch (NoSuchMethodException e) {throw new RuntimeException(e);} catch (InvocationTargetException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);} catch (InstantiationException e) {throw new RuntimeException(e);}return res;}

通过命令编译为 exe 文件

image.png

运行exe文件后,通过浏览器发起请求。

在HelloController中。通过反射的方式使用到了UserEntity的无参构造方法。如果不做任何处理。那么打成二进制可执行文件后是执行不了的,可以通过 Runtime Hints 机制来处理。

RuntimeHintsRegistrar

官网提供的解决方案,自定义一个RuntimeHintsRegistrar接口的实现类,然后把该实现类注入到Spring中

image.png

@RestController
@ImportRuntimeHints(HelloController.UserEntityRuntimeHints.class)
public class HelloController {@GetMapping("/hello")public String hello(){String res = "hello";try {Method hello = UserEntity.class.getMethod("hello");res =  (String)hello.invoke(UserEntity.class.newInstance(),null);} catch (NoSuchMethodException e) {throw new RuntimeException(e);} catch (InvocationTargetException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);} catch (InstantiationException e) {throw new RuntimeException(e);}return res;}static class UserEntityRuntimeHints implements RuntimeHintsRegistrar{@Overridepublic void registerHints(RuntimeHints hints, ClassLoader classLoader) {try {hints.reflection().registerConstructor(UserEntity.class.getConstructor(), ExecutableMode.INVOKE);} catch (NoSuchMethodException e) {throw new RuntimeException(e);}}}
}

SpringBoot中AOT核心代码

执行 mvn -Pnative native:compile时会执行GraalVM中的相关指令。最终会调用SpringApplicationAotProcessor中的main 方法来完成相关提前编译操作。

	public static void main(String[] args) throws Exception {int requiredArgs = 6; // 调用main方法接收的有6个参数Assert.isTrue(args.length >= requiredArgs, () -> "Usage: " + SpringApplicationAotProcessor.class.getName()+ " <applicationName> <sourceOutput> <resourceOutput> <classOutput> <groupId> <artifactId> <originalArgs...>");// 获取SpringBoot项目的入口classClass<?> application = Class.forName(args[0]);// 通过传递过来的参数完成相关生成目录的配置Settings settings = Settings.builder().sourceOutput(Paths.get(args[1])).resourceOutput(Paths.get(args[2])).classOutput(Paths.get(args[3])).groupId((StringUtils.hasText(args[4])) ? args[4] : "unspecified").artifactId(args[5]).build();String[] applicationArgs = (args.length > requiredArgs) ? Arrays.copyOfRange(args, requiredArgs, args.length): new String[0];// 执行 process 方法new SpringApplicationAotProcessor(application, settings, applicationArgs).process();}
	public final T process() {try {// 设置状态System.setProperty(AOT_PROCESSING, "true");return doProcess(); // 处理的核心方法}finally {System.clearProperty(AOT_PROCESSING);}}
 	@Overrideprotected ClassName doProcess() {deleteExistingOutput(); // 删除已经存在的目录// 启动SpringBoot服务  但是不会做扫描beanGenericApplicationContext applicationContext = prepareApplicationContext(getApplicationClass());return performAotProcessing(applicationContext);}
	@Overrideprotected GenericApplicationContext prepareApplicationContext(Class<?> application) {return new AotProcessorHook(application).run(() -> {Method mainMethod = application.getMethod("main", String[].class);return ReflectionUtils.invokeMethod(mainMethod, null, new Object[] { this.applicationArgs });});}

此时会执行启动类中的main方法来启动SpringBoot

image.png

在启动中创建Spring上下文对象时会做如下的处理

	private ConfigurableApplicationContext createContext() {if (!AotDetector.useGeneratedArtifacts()) {return new AnnotationConfigServletWebServerApplicationContext();}return new ServletWebServerApplicationContext();}

如果没有使用AOT,那么就会创建AnnotationConfigServletWebServerApplicationContext,它里面会添ConfigurationClassPostProcessor,从而会解析配置类。而如果使用了AOT,则会创建ServletWebServerApplicationContext,它就是一个空容器,它里面没有ConfigurationClassPostProcessor,所以后续不会触发扫描了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/84525.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【SpringCloud】微服务技术栈入门1 - 远程服务调用、Eureka以及Ribbon

目录 远程服务调用RestTemplate Eureka简要概念配置 Eureka 环境设置 Eureka ClientEureka 服务发现 Ribbon工作流程配置与使用 Ribbon饥饿加载 远程服务调用 RestTemplate RestTemplate 可以模拟客户端来向另外一个后端执行请求 黑马给出的微服务项目中&#xff0c;有两个 …

yolov5使用最新MPDIOU损失函数,有效和准确的边界盒回归的损失,优于GIoU/EIoU/CIoU/EIoU(附代码可用)

文章目录 1. 论文1.1. 主要目的1.2. 设计思路2 代码3.总结1. 论文 MPDIoU: A Loss for Efficient and Accurate Bounding Box Regression (一个有效和准确的边界框损失回归函数) 论文地址 1.1. 主要目的 当预测框与边界框具有相同的纵横比,但宽度和高度值完全不同时,大多数…

20230918使用ffmpeg将mka的音频转为AAC编码以便PR2023来识别

20230918使用ffmpeg将mka的音频转为AAC编码以便PR2023来识别 2023/9/18 20:58 ffmpeg -i 1.mka -acodec aac 1.mp4 ffmpeg -i 1.mka -vn -c:a aac 2.aac ffmpeg -i 1.mka -vn -c:a aac 2.MP4 ffmpeg mka 转 aacmp4 https://avmedia.0voice.com/?id42526 用ffmpeg将mka格式转化…

云端IDE的技术选型1

背景 考虑到以下几点&#xff0c;准备给低代码平台开发一套云端的IDE&#xff1a; 桌面端IDE&#xff1a;vs code 或 idea&#xff0c;都有需要开发人员安装ide&#xff0c;以及配置环境很多时候&#xff0c;配置开发环境是个非常曲折过程&#xff0c;经常出现版本不匹配&…

【分布式计算】副本数据Replicated Data

作用&#xff1a;可靠性、高性能、容错性 问题&#xff1a;如何保持一致、如何更新 问题&#xff1a;存在读写/写写冲突 一个简单的方法就是每个操作都保持顺序&#xff0c;但是因为网络延迟会导致问题 Data-centric models: consistency model?? ??? 读取时&#xff0c…

深入理解WPF中MVVM的设计思想

近些年来&#xff0c;随着WPF在生产&#xff0c;制造&#xff0c;工业控制等领域应用越来越广发&#xff0c;很多企业对WPF开发的需求也逐渐增多&#xff0c;使得很多人看到潜在机会&#xff0c;不断从Web&#xff0c;WinForm开发转向了WPF开发&#xff0c;但是WPF开发也有很多…

图像处理软件Photoshop 2024 mac新增功能

Photoshop 2024 mac是一款图像处理软件的最新版本。ps2024提供了丰富的功能和工具&#xff0c;使用户能够对照片、插图、图形等进行精确的编辑和设计。 Photoshop 2024 mac软件特点 快速性能&#xff1a;Photoshop 2024 提供了更快的渲染速度和更高效的处理能力&#xff0c;让用…

MyBatis 缓存模块

文章目录 前言缓存的实现Cache接口PerpetualCache 缓存的应用缓存对应的初始化一级缓存二级缓存第三方缓存 前言 MyBatis作为一个强大的持久层框架&#xff0c;缓存是其必不可少的功能之一&#xff0c;Mybatis中的缓存分为一级缓存和二级缓存。但本质上是一样的&#xff0c;都…

【异常错误】detected dubious ownership in repository ****** is owned by: ‘

今天在github git的时候&#xff0c;突然出现了这种问题&#xff0c;下面的框出的部分一直显示&#xff1a; detected dubious ownership in repository at D:/Pycharm_workspace/SBDD/1/FLAG D:/Pycharm_workspace/SBDD/1/FLAG is owned by: S-1-5-32-544 but the current use…

多线程的学习第二篇

多线程 线程是为了解决并发编程引入的机制. 线程相比于进程来说,更轻量 ~~ 更轻量的体现: 创建线程比创建进程,开销更小销毁线程比销毁进程,开销更小调度线程比调度进程,开销更小 进程是包含线程的. 同一个进程里的若干线程之间,共享着内存资源和文件描述符表 每个线程被独…

外国固定资产管理系统功能有哪些

很多公司都在寻找提高自己资产管理效益的方法。为了满足这一要求&#xff0c;国外的固定资产管理系统已经发展成多种形式。以下是国外一些常见的固定资产管理系统的特点:自动化和智能化:许多现代固定资产管理系统采用自动化和数字化技术&#xff0c;以简化流程&#xff0c;减少…

网络编程day04(网络属性函数、广播、组播、TCP并发)

今日任务 对于newfd的话&#xff0c;最好是另存然后传入给分支线程&#xff0c;避免父子线程操作同一个文件描述符 1.广播&#xff1a; 接收端 代码&#xff1a; #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h&…

Databend 开源周报第 111 期

Databend 是一款现代云数仓。专为弹性和高效设计&#xff0c;为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务&#xff1a;https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend 。 理解 SHARE END…

大数据(九):数据可视化(一)

专栏介绍 结合自身经验和内部资料总结的Python教程&#xff0c;每天3-5章&#xff0c;最短1个月就能全方位的完成Python的学习并进行实战开发&#xff0c;学完了定能成为大佬&#xff01;加油吧&#xff01;卷起来&#xff01; 全部文章请访问专栏&#xff1a;《Python全栈教…

Linux_9_网络协议和管理

目录 1网络基础1.1 网络概念1.2常见的网络物理组件1.3网络应用程序1.3.1各种网络应用1.3.2应用程序对网络的要求 1.4网络的特征1.4.1速度(带宽)1.4.2网络拓扑 1.5网络1.5.1网络准和分层1.5.2开放系统互联OSI1.5.3网络的通信过程1.5.3.1数据封装和数据解封1.5.3.2协议数据单元PD…

基于javaweb的顶岗实习管理系统(jsp+servlet)

系统简介 本项目采用eclipse工具开发&#xff0c;jspservletjquery技术编写&#xff0c;数据库采用的是mysql&#xff0c;navicat开发工具。 三个角色&#xff1a;管理员&#xff0c;教师&#xff0c;学生 模块简介 管理员&#xff1a; 1、登录 2、学生管理 3、公告管理 …

如何通过一键导出导入数据实现批量重命名文件名称

在日常办公中&#xff0c;我们经常需要对大量的文件进行重命名&#xff0c;以便更好地管理和查找文件。而且&#xff0c;有时候我们还需要将文件名称翻译成其他语言&#xff0c;以适应不同的工作需求。如何高效地完成这项任务呢&#xff1f;接下来&#xff0c;我将介绍一种方法…

【李沐深度学习笔记】线性代数实现

课程地址和说明 线性代数实现p2 本系列文章是我学习李沐老师深度学习系列课程的学习笔记&#xff0c;可能会对李沐老师上课没讲到的进行补充。 这节就算之前内容的复习&#xff0c;后面以截图形式呈现 标量由只有一个元素的张量表示 import torch x torch.tensor([3.0]) y …

Spring Boot魔法:简化Java应用的开发与部署

文章目录 什么是Spring Boot&#xff1f;1. 自动配置&#xff08;Auto-Configuration&#xff09;2. 独立运行&#xff08;Standalone&#xff09;3. 生产就绪&#xff08;Production Ready&#xff09;4. 大量的起步依赖&#xff08;Starter Dependencies&#xff09; Spring …

免杀对抗-java语言-shellcode免杀-源码修改+打包exe

JAVA-ShellCode免杀-源码修改&打包EXE Shellcode-生成/上线 1.msf生成shellcode 命令&#xff1a;msfvenom -p java/meterpreter/reverse_tcp LHOSTx.x.x.x LPORTxxxx -f jar -o msf.jar 2.msf设置监听 3.执行msf生成的shellcode jar包&#xff0c;成功上线 命令&#xff1…