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

Spring Boot应用使用GraalVM本地编译相关配置

1. 介绍

Java应用程序可以通过Graalvm Native Image提前编译生成与本地机器相关的可执行文件。与在JVM执行java程序相比,Native Image占用内存更小和启动速度更快。

从spring boot3开始支持GraalVM Native Image,因此要使用此特性,需要把spring boot升级到3.0.0以上, 其中,JDK也要升级到17以上。

官方提供的示例见Developing Your First GraalVM Native Application。示例代码与普通spring boot一样,可以忽略,继续看下面内容。

1.1 maven插件配置

示例中与spring boot项目一样,不同之处在于打包配置,比如maven pom.xml文件中需要加上graalvm的native-maven-plugin插件,如下:

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.3.0</version><relativePath/>
</parent><!--省略--><dependencies>
<!--省略-->
</dependencies><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>

pom说明:<parent>项指定为spring-boot-starter-parent,这样你就可以减少许多配置,就像上面一样。
spring-boot-starter-parent中为生成Native Image定义了名为native的profile,打包生成可执行文件使用如下maven命令

mvn clean package -Pnative

1.2 maven插件完整配置

如果pom的<parent>项不是spring-boot-starter-parent,你就需要像如下配置

<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><version>3.3.0</version><configuration><archive><manifestEntries><Spring-Boot-Native-Processed>true</Spring-Boot-Native-Processed></manifestEntries></archive></configuration>
</plugin>
<plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>3.3.0</version><configuration><image><builder>paketobuildpacks/builder-jammy-tiny:latest</builder><env><BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE></env></image></configuration><executions><execution><id>process-aot</id><goals><goal>process-aot</goal></goals></execution></executions>
</plugin>
<plugin><groupId>org.graalvm.buildtools</groupId><artifactId>native-maven-plugin</artifactId><version>0.10.2</version><configuration><classesDirectory>${project.build.outputDirectory}</classesDirectory></configuration><executions><execution><id>add-reachability-metadata</id><goals><goal>add-reachability-metadata</goal></goals></execution></executions>
</plugin>

2. 开发注意事项

Spring Boot对自身提供的bean自动注入、AOP配置、factories等特性做了Native支持,在静态编译期间相关类都可达,
但我们的项目中还有些不受spring AOT支持的代码,比如业务代码中的反射、JSON和对象转换、以及三方jar包中动态代码等。
我们需要手动配置提供hint,graalvm才能把这些动态代码编译到可执行文件中去,否则执行时会抛出异常。

2.1 项目中动态代码支持

提供动态代码的hint配置,有三种方式:

  1. 第一种遵从graalvm规范提供相应的json配置,这个可以见往期分享Graalvm配置文件与Feature和Substitute机制介绍
  2. 第二种扩展Spring接口,即实现RuntimeHintsRegistrar接口,通过代码指定哪些类、资源需要hint。
  3. 第三种反射类可以使用@RegisterReflectionForBinding由spring自动绑定反射配置。

下面介绍后面两种方式

2.1.1 扩展Spring接口RuntimeHintsRegistrar

  1. 示例代码如下:
    public class MyAOTRuntimeHints implements RuntimeHintsRegistrar {@Overridepublic void registerHints(RuntimeHints hints, ClassLoader classLoader) {// Register method for reflection//        Method method = ReflectionUtils.findMethod(MyClass.class, "sayHello", String.class);//        hints.reflection().registerMethod(method, ExecutableMode.INVOKE);// 反射注册hints.reflection().registerType(UserModel.class, typeHint -> {typeHint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,MemberCategory.INVOKE_DECLARED_METHODS,MemberCategory.DECLARED_FIELDS);});// 资源文件注册hints.resources().registerPattern("resource_hint.properties");// Serialization类注册hints.serialization().registerType(Email.class);// 代理注册// hints.proxies().registerJdkProxy(MyInterface.class);}
    }
    
  2. 注册Hint类。MyAOTRuntimeHints还需要使用@ImportRuntimeHints注解到任何@Configuration class,或者在META-INF/aot.factories文件注册
    1. 使用@ImportRuntimeHints
      @Configuration
      @ImportRuntimeHints(value = {MyAOTRuntimeHints.class})
      public class AOTConfiguration {}
      
    2. 注册META-INF/aot.factories
      org.springframework.aot.hint.RuntimeHintsRegistrar=com.example.springnative.aot.hit.MyAOTRuntimeHints
      

2.1.2 使用注解@RegisterReflectionForBinding

对于项目中使用反射的地方,可以直接通过注解来配置hint,把@RegisterReflectionForBinding注解到任何@Configuration class类上。
示例如下:

@Configuration
@RegisterReflectionForBinding(classes = {MyJSONBean.class})
public class AOTConfiguration {}

2.2 代码中隐式使用反射的地方

2.2.1 JSON

json工具推荐使用jackson,spring中也对其做了支持。
把对象转为json或把json转为对象,对象中所有类都要注册反射hint。
如UserModel在在reflect-config.json配置如下

{
"name": "com.example.springnative.model.UserModel",
"allPublicConstructors": true,
"allDeclaredFields": true,
"allPublicMethods": true
}

如果javabean实现了java.io.Serializable接口,可以在serialization-config.json中注册,示例如下。

{
"name": "com.example.springnative.model.UserModel"
}

2.3 Configuration Properties类嵌套

如果Properties类嵌套了其它类型,则必须要使用@NestedConfigurationProperty注解,否则spring AOT没法识别到这个嵌套类,就不能为其注册反射hint。如下示例。

@ConfigurationProperties(prefix = "my.properties")
public class MyProperties {@NestedConfigurationPropertyprivate final Nested nested = new Nested();// getters / setters...
}public class Nested {private int number;// getters / setters...}

2.4 Native Image执行与JVM执行区别

  1. 应用程序类路径在生成时是固定的,不能更改。
  2. 没有延迟类加载,可执行文件中提供的所有内容都将在启动时加载到内存中。
  3. 应用程序中定义的Bean不能在运行时更改,即bean创建相关的条件配置在编译后就不能再更改。
    如@Profile注解及类似配置不能更改,@ConditionalOnProperty中的条件值不能更改,即使更改也不会生效,因为bean已经创建了。

3. 原理简述

  1. Spring AOT Processor会启动应用main方法开始静态分析,并生成BeanDefinition对象,但不会创建bean
  2. 分析阶段不可达的代码将被忽略,不会编译到可执行文件中。
  3. 在编译前会生成java代码来创建BeanDefinition对象。源码存放到target/spring-aot/main/sources
  4. AOP原本在运行时动态生成的字节码,但在编译时就必须生成,动态字节码存放在target/spring-aot/main/classes
  5. Spring AOT Processor生成native需要的hint文件,存放到target/spring-aot/main/resources
  6. Spring boot把所有生成的文件都编译到jar包中,关于hint文件都放到jar包的META-INF/native-image目录下,graalvm静态编译时会获取该目录下的hint配置文件。

4. 官方文档阅读

Known GraalVM Native Image limitations

Testing GraalVM Native Images

Introducing GraalVM Native Images

5. 总结

  1. maven插件配置有两种方式,
    1. 一种是pom的parent指定为spring-boot-starter-parent后简单引入spring的spring-boot-maven-plugin和graalvm的native-maven-plugin插件
    2. 另一种是完整的配置spring的spring-boot-maven-plugin插件指定process-aot目标,配置graalvm的native-maven-plugin插件指定add-reachability-metadata目标
  2. 动态代码需要由开发者指定hint配置,有3种方式:
    1. 使用graalvm原生支持的方式,在META-INF/native-image目录下添加反射、代理、JNI等相关json配置。
    2. 实现RuntimeHintsRegistrar接口通过代码方式注册hint配置。
    3. 反射类可以使用@RegisterReflectionForBinding由spring自动绑定反射配置。
  3. 编译后影响bean创建相关的配置在运行期间不起作用,如@ConditionalOnProperty中的条件。

相关文章:

Spring Boot应用使用GraalVM本地编译相关配置

1. 介绍 Java应用程序可以通过Graalvm Native Image提前编译生成与本地机器相关的可执行文件。与在JVM执行java程序相比&#xff0c;Native Image占用内存更小和启动速度更快。 从spring boot3开始支持GraalVM Native Image&#xff0c;因此要使用此特性&#xff0c;需要把sp…...

代码的坏味道——长函数

前言&#xff1a;一个函数应该尽量做一件事情&#xff0c;如果非要做多个事情&#xff0c;要做函数提取&#xff0c;每次迭代应该考虑到是否有重复代码或者可以优化的代码。 长函数&#xff1a;长函数的产生&#xff1a; 逻辑是平铺直叙的需求迭代没有考虑优化&#xff0c;一次…...

【机器学习】基于密度的聚类算法:DBSCAN详解

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 基于密度的聚类算法&#xff1a;DBSCAN详解引言DBSCAN的基本概念点的分类聚类过…...

Qt 网络编程 网络信息获取操作

学习目标&#xff1a;网络信息获取操作 前置环境 运行环境:qt creator 4.12 学习内容 一、Qt 网络编程基础 Qt 直接提供了网络编程模块,包括基于 TCP/IP 的客户端和服务器相关类,如 QTcpSocket/QTcpServer 和 QUdpSocket,以及实现 HTTP、FTP 等协议的高级类,如 QNetworkRe…...

linux中的进程以及进程管理

程序和进程的区别和联系 程序&#xff08;Program&#xff09;&#xff1a; 程序是一组指令的集合&#xff0c;通常存储在磁盘或其他存储设备上&#xff0c;是一种静态的概念。程序本身并没有运行&#xff0c;它只是一个可执行的文件或脚本&#xff0c;包含了一系列的指令和数…...

pyecharts可视化案例大全(11~20)

pyecharts可视化案例大全(11~20) 十一、设置动画效果十二、直方图带视觉组件十三、设置渐变色(线性渐变)十四、设置渐变色(径向渐变)十五、设置分割线十六、设置分隔区域十七、面积图十八、堆叠面积图十九、自定义线样式二十、折线图平滑处理十一、设置动画效果 在图表加载前…...

Docker在人工智能领域的应用与实战

摘要 人工智能&#xff08;AI&#xff09;技术的快速发展带来了对高效开发和部署工具的需求。Docker作为一个创新的容器化平台&#xff0c;为AI领域提供了强大的支持。本文详细介绍了Docker在AI模型开发、训练、部署以及服务器集群管理等方面的应用&#xff0c;并探讨了其在数…...

python基础篇(8):异常处理

在Python编程中&#xff0c;异常是程序运行时发生的错误&#xff0c;它会中断程序的正常执行流程。异常处理机制使得程序能够捕获这些错误&#xff0c;并进行适当的处理&#xff0c;从而避免程序崩溃。 1 错误类型 代码的错误一般会有语法错误和异常错误两种&#xff0c;语法错…...

FortiClient 用IPsec VPN 远程拨号到FortiGate说明文档

说明&#xff1a;本文档针对IPsec VPN 中的Remote VPN 进行说明&#xff0c;即远程用户使用PC中的FortiClient软件&#xff0c;通过VPN拨号的方式连接到公司总部FortiGate设备&#xff0c;访问公司内部服务器。在配置之前需要统一VPN策略和参数&#xff0c;如模式… 说明&#…...

Git-Unity项目版本管理

目录 准备GitHub新建项目并添加ssh密钥Unity文件夹 本文记录如何用git对unity 项目进行版本管理&#xff0c;并可传至GitHub远端。 准备 名称版本windows11Unity2202.3.9.f1gitN.A.githubN.A. GitHub新建项目并添加ssh密钥 GitHub新建一个repositorywindows11 生成ssh-key&…...

每日一题~ leetcode 402 (贪心+单调栈)

click me! 这个贪心的推导在leetcode上已经很明确了。 click me! 删除k个数&#xff0c;可以先考虑删除一个数。这也是一种常见的思路。&#xff08;如果进行同样的操作多次&#xff0c;可以先只 考虑一次操作如何实现&#xff0c;或者他的影响。完成这一次操作后&#xff0c;…...

设计模式之模版方法

模版方法介绍 模版方法&#xff08;Template Method&#xff09;模式是一种行为型设计模式&#xff0c;它定义了一个操作&#xff08;模板方法&#xff09;的基本组合与控制流程&#xff0c;将一些步骤&#xff08;抽象方法&#xff09;推迟到子类中&#xff0c;使得子类可以在…...

docker部署redis/mongodb/

一、redis 创建/root/redis/conf/redis.conf 全部执行命令如下 docker run -it -d --name redis -p 6379:6379 --net mynet --ip 172.18.0.9 -m 400m -v /root/redis/conf:/usr/local/etc/redis -e TXAsia/Shangehai redis redis-server /usr/local/etc/redis/redis.conf 部署…...

LeetCode 581. 最短无序连续子数组

更多题解尽在 https://sugar.matrixlab.dev/algorithm 每日更新。 组队打卡&#xff0c;更多解法等你一起来参与哦&#xff01; LeetCode 581. 最短无序连续子数组&#xff0c;难度中等。 排序 解题思路&#xff1a;首先对数组排序&#xff0c;然后找出两侧顺序的数组&#x…...

数据库可视化管理工具dbeaver试用及问题处理。

本文记录了在内网离线安装数据库可视化管理工具dbeaver的过程和相关问题处理方法。 一、下载dbeaver https://dbeaver.io/download/ 笔者测试时Windows平台最新版本为&#xff1a;dbeaver-ce-24.1.1-x86_64-setup.exe 二、安装方法 一路“下一步”即可 三、问题处理 1、问…...

29、php实现和为S的两个数字(含源码)

题目&#xff1a;php 实现 和为S的两个数字 描述&#xff1a; 输入一个递增排序的数组和一个数字S&#xff0c;在数组中查找两个数&#xff0c; 是的他们的和正好是S&#xff0c;如果有多对数字的和等于S&#xff0c;输出两个数的乘积最小的。 输出描述&#xff1a; 对应每个测…...

Spring Boot中的全局异常处理

Spring Boot中的全局异常处理 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将探讨如何在Spring Boot应用中实现全局异常处理&#xff0c;这是保证应用…...

中英双语介绍美国苹果公司(Apple Inc.)

中文版 苹果公司简介 苹果公司&#xff08;Apple Inc.&#xff09;是一家美国跨国科技公司&#xff0c;总部位于加利福尼亚州库比蒂诺。作为全球最有影响力的科技公司之一&#xff0c;苹果以其创新的产品和设计引领了多个科技领域的变革。以下是对苹果公司发展历史、主要产品…...

C语言牢大坠机

目录 开头程序程序的流程图《牢大坠机》结尾 开头 大家好&#xff0c;我叫这是我58&#xff0c;今天&#xff0c;我们要来看关于牢大坠机的一些东西。 程序 #define _CRT_SECURE_NO_WARNINGS 1 #define HIGH 66 #include <stdio.h> #include <Windows.h> int ma…...

zdppy+vue3+antd 实现表格单元格编辑功能

初步实现 <template><a-button class"editable-add-btn" style"margin-bottom: 8px" click"handleAdd">Add</a-button><a-table bordered :data-source"dataSource" :columns"columns"><templa…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别

UnsatisfiedLinkError 在对接硬件设备中&#xff0c;我们会遇到使用 java 调用 dll文件 的情况&#xff0c;此时大概率出现UnsatisfiedLinkError链接错误&#xff0c;原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用&#xff0c;结果 dll 未实现 JNI 协…...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

Vue ③-生命周期 || 脚手架

生命周期 思考&#xff1a;什么时候可以发送初始化渲染请求&#xff1f;&#xff08;越早越好&#xff09; 什么时候可以开始操作dom&#xff1f;&#xff08;至少dom得渲染出来&#xff09; Vue生命周期&#xff1a; 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...