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.rhkb.cn/news/137928.html

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

相关文章

JWT安全及案例实战

文章目录 JWT 安全1. Cookie2. Session3. Token4. JWT4.1 JWT概述4.1.1 JWT头4.1.2 有效载荷4.1.3 签名哈希4.1.4 通信流程 4.2 JWT 漏洞描述4.3 JWT 漏洞原理4.4 JWT 安全防御 5. WebGoat 靶场实验5.1 第四关5.2 第五关5.3 第七关 越权与逻辑漏洞 Web漏洞点只有一个入口&#…

Direct3D融合技术

该技术能使我们将当前要进行光栅化的像素的颜色与先前已已光栅化并处于同一位置的像素的颜色进行合成&#xff0c;即将正在处理的图元颜色值与存储在后台缓存中的像素颜色值进行合成(混合)&#xff0c;利用该技术我们可得到各种各样的效果&#xff0c;尤其是透明效果。 在融合…

云渲染是怎么做到不排队的

云渲染排队严重影响了用户的使用体验&#xff0c;还会导致用户的流失&#xff0c;因此解决渲染不排队的问题对于云渲染平台来说是非常重要的。而作为云渲染平台&#xff0c;自己的机器基本都是固定的&#xff0c;哪如何解决用户渲染排队的问题呢&#xff1f;我们一起来看看全国…

天地图绘制区域图层

背景&#xff1a; 业务方要求将 原效果图 参考效果图 最终实现效果 变更点&#xff1a; 1.将原有的高德地图改为天地图 2.呈现形式修改&#xff1a;加两层遮罩&#xff1a;半透明遮罩层mask区域覆盖物mask 实现过程&#xff1a; 1.更换地图引入源 <link rel"style…

免杀对抗-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…

网络安全第一次作业

1、什么是防火墙 防火墙是一种网络安全系统&#xff0c;它根据预先确定的安全规则监视和控制传入和传出的网络流量。其主要目的是阻止对计算机或网络的未经授权的访问&#xff0c;同时允许合法通信通过。 防火墙可以在硬件、软件或两者的组合中实现&#xff0c;并且可以配置为根…

西部数据硬盘查询

保修状态 | WD 支持 保修状态 | WD 支持 https://support-cn.wd.com/app/warrantystatusweb https://support-cn.wd.com/app/warrantystatusweb 选择大陆

【C++】STL—— unordered_map的介绍和使用、 unordered_map的构造函数和迭代器、 unordered_map的增删查改函数

文章目录 1. unordered_map的介绍2. unordered_map的使用2.1unordered_map的构造函数2.2unordered_map的迭代器2.3unordered_map的容量和访问函数2.4unordered_map的增删查改函数 1. unordered_map的介绍 unordered_map的介绍 &#xff08;1&#xff09;unordered_map是存储&l…

Vue路由与node.js环境搭建

目录 前言 一.Vue路由 1.什么是spa 1.1简介 1.2 spa的特点 1.3 spa的优势以及未来的挑战 2.路由的使用 2.1 导入JS依赖 2.2 定义两个组件 2.3 定义组件与路径对应关系 2.4 通过路由关系获取路由对象 2.5 将对象挂载到vue实例中 2.6 定义触发路由事件的按钮 2.7 定…

JavaScript小案例-tab栏切换(可移除item)

gif效果图&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>tab栏切…

看完100%会写毕业论文

写论文是每个学术研究者都要面对的任务之一&#xff0c;在开始写论文之前&#xff0c;准备工作是至关重要的。本文将介绍一些写论文准备工作的重要步骤&#xff0c;并且探讨如何利用AI写作大师辅助来提高写作效率和质量&#xff0c;让你看完100%会写毕业论文。 01 — 了解论文…

键盘失灵按什么键恢复?详细方法分享!

“我的电脑键盘莫名其妙失灵了&#xff0c;试了好多方法都无法恢复。请问遇到键盘失灵的情况&#xff0c;应该按什么键才能恢复呢&#xff1f;” 键盘是计算机的重要输入设备之一&#xff0c;但有时候它可能会出现失灵的情况&#xff0c;让用户感到困惑和不知所措。但其实&…

【实战案例】技术转项目经理容易踩的坑,我都踩了

“带团队容易&#xff0c;带好团队难。” 这是身边一位项目经理近期在团队管理方面的深刻感悟。目前&#xff0c;他手上的一个项目被迫暂停了&#xff0c;项目团队也散了。下面给大家简要分享下这个项目案例。 【案例分享】 小李负责的是一个二次开发的项目&#xff0c;所涉及…

导览软件定制开发方案

随着智能手机的普及和人们对文化、旅游等方面的需求不断增加&#xff0c;导览软件市场前景广阔。本文将围绕导览软件定制开发方案展开&#xff0c;包括以下部分&#xff1a; 一、行业现状及市场需求 导览软件市场发展迅速&#xff0c;各类导览软件层出不穷。通过对市场…

alist windows 命令行版本下载、使用

下载 下载地址 https://github.com/alist-org/alist/releases 文件下载链接 &#xff0c;直接点击就能下载https://github.com/alist-org/alist/releases/download/v3.27.0/alist-windows-arm64.zip 安装 输入cmd&#xff0c;按enter键&#xff0c;会调出cmd命令行 输入 alis…

数组扁平化的方法

什么是“数组扁平化” 用简单的话来说&#xff0c;就是将一个多维数组变为一个一维数组。例如&#xff0c;将数组[1, 2, [3, [4, 5]], [6, 7]]扁平化处理后输出[1, 2, 3, 4, 5, 6, 7]。 实现“数组扁平化”方法 方式1&#xff1a;使用基础的递归遍历 声明一个函数&#xff0c…

《Linux操作系统实战》| 面试了两个实习生,Linux 基本命令都不会(一)

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。&#x1f60a; 座右铭&#xff1a;不想…

python进程和线程(05)

python进程和线程(05) 文章目录 python进程和线程(05)1 python进程和线程1.1 进程和线程概念1.2 并行执行1.3 核心使用语法_threading模块1.4 多线程编程1.4.1 案例单线程不能满足情况如下&#xff1a;1.4.2 多线程1.4.2.1 多线程创建语句1.4.2.2 案例 1.4.2 多线程传参使用1.4…

基于微信小程序的小区服务管理系统设计与实现(源码+lw+部署文档+讲解等)

前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f447;&#x1f3fb;…

【算法基础】数学知识

质数 质数的判定 866. 试除法判定质数 - AcWing题库 时间复杂度是logN #include<bits/stdc.h> using namespace std; int n; bool isprime(int x) {if(x<2) return false;for(int i2;i<x/i;i){if(x%i0) return false;}return true; } signed main() {cin>&g…