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

java瘦身、升级graalvm

一.graalvm简介

传统的hotvm,需要先启动 jvm 再载入 java 代码,然后再即时的将 .class 字节码编译成机器码,交给机器执行。以在线权限为例,通过打包插件会将项目打成jar包,jar里是class文件,包含自定义代码和maven引用的所有包。

graalvm使用了 Ahead-of-time compile(提前编译),也就是说,他在编译期时,会把所有相关的东西,包含一个基底的 VM,一起编译成机器码,这个基底 VM 是 GraalVM 内部才有的东西,他只包含最基本的线程排成机制、垃圾回收,尽可能的缩小必要的 jvm 体积。通过graalvm打包插件,仅会把实际用到的代码打成一个可执行文件。

graalvm aot功能,运行时省去了加载class这个过程,同时只把相关代码编译,避免传统打包将所有依赖的包都编译,所以省去了类加载的内存空间。

二.版本选择

项目大多使用springboot,需要使用spring的打包插件,springboot2.x的打包插件是实验性的,所以使用springboot3正式版。

springBoot3.3.10:当前最新版本是3.4.5,选择稍早一些的3.3.10稳定版。

oracle jdk17:

  • springboot3.x只支持jdk17-23,当前jdk长期支持稳定版有8、11、17、21,17发布于2021年,21发布于2023年,选择较早的17。

  • openjdk17的graalvm只免费使用Serial GC回收器,g1回收器是商用收费,oracle g1是免费的,所以选择oracle。

三.升级过程

升级jdk17

电脑有多个jdk版本,推荐使用sdkman控制多版本。

使用sdk安装graalvmjdk17:sdk install java 22.3.r17-nik

升级springboot3.3.10

参考Springboot2.x升级到3.x的经验分享 - 盗梦笔记 - 博客园

打包graalvm

操作步骤

推荐在ubuntu进行打包更简单,需要安装graalvm相关文件,在windows安装过程复杂。

在安装好graalvm jdk之后,安装native-image和相关工具,参考ubuntu 安装 graalvm

在pom中添加插件,注意修改启动类

<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>3.3.10</version></plugin><plugin><groupId>org.graalvm.buildtools</groupId><artifactId>native-maven-plugin</artifactId><configuration><mainClass>com.example.demo.DemoApplication</mainClass><buildArgs><buildArg>-H:+AddAllCharsets</buildArg><buildArg>--initialize-at-run-time=org.apache.logging.log4j.LogManager</buildArg><buildArg>--initialize-at-run-time=org.apache.logging.log4j.util.ProviderUtil</buildArg><buildArg>--initialize-at-run-time=org.apache.logging.log4j.spi.Provider</buildArg></buildArgs></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><configuration><skip>true</skip></configuration></plugin></plugins></build><repositories><repository><id>spring-snapshots</id><name>Spring Snapshots</name><url>https://repo.spring.io/snapshot</url><releases><enabled>false</enabled></releases></repository></repositories><pluginRepositories><pluginRepository><id>spring-snapshots</id><name>Spring Snapshots</name><url>https://repo.spring.io/snapshot</url><releases><enabled>false</enabled></releases></pluginRepository></pluginRepositories>

执行mvn clean package 打jar包

在target目录下,执行java -agentlib:native-image-agent=config-output-dir=<跟踪代理文件输出路径> -jar <jar 包路径>

这个命令会启动jar包,启动后,把所有代码都执行一遍。如果有部分代码没有执行、这部分有用到新类,则生成的配置文件就会缺少未执行的这部分的类反射信息,后续graalvm包运行后调用这部分功能会报错。

把jar运行停掉,就会生成配置文件,如下图,reflect-config文件是反射信息,resource-config是资源文件信息。如。当然这些文件可以手动修改,如果扫描不全面,可以手动加。

在工程resource目录下新建 META-INF/native-image 文件夹,并且将所有生成的配置文件移入。

在工程中自己添加 mvnw命令和目录

执行打包 ./mvnw -Pnative native:compile

或者 ./mvnw -Pnative native:compile -Dmaven.repo.local=/home/melo/apache-maven-3.9.9-bin/repository (指定本地仓库,mvnw用不上默认mvn配置,防止多module找不到)

打包很占用内存,需要6-10G内存,打包结束后会生成一个可执行文件,可直接运行。

事务、反射、动态代理

spring事务基于动态代理,所有动态代理和反射要提前在reflect文件中指定要反射哪些类,graalvm打包才会将类包含。

运行期间如果出现java.lang.TypeNotPresentException、 java.lang.ClassNotFoundException就是此类问题,需要在java -agentlib:native-image-agent生成配置文件期间,尽量把所有代码运行。如果运行后还报错,就手动加入反射配置。

maven多module

以权限为例,parent包含三个module,authenticate依赖authorize,authorize依赖common。

在common和authorize pom中使用以下插件,其他插件都删除

	<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>${java.version}</source><target>${java.version}</target></configuration></plugin></plugins></build>

在authenticate pom中使用以下插件,注意修改为自己工程的启动类全路径

<build><finalName>security_online_server</finalName><sourceDirectory>main/java</sourceDirectory><outputDirectory>target/classes</outputDirectory><resources><resource><directory>main/java</directory><filtering>false</filtering></resource><resource><directory>main/resources</directory><filtering>true</filtering><excludes><exclude>*.ico</exclude><exclude>*/*.ico</exclude><exclude>*/*/*.ico</exclude><exclude>*/*/*/.ico</exclude></excludes></resource><resource><directory>main/resources</directory><filtering>false</filtering><includes><include>*.ico</include><include>*/*.ico</include><include>*/*/*.ico</include><include>*/*/*/*.ico</include></includes></resource></resources><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>3.3.10</version></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-resources-plugin</artifactId><version>3.1.0</version><configuration><encoding>UTF-8</encoding><nonFilteredFileExtensions><nonFilteredFileExtension>cer</nonFilteredFileExtension><nonFilteredFileExtension>keystore</nonFilteredFileExtension></nonFilteredFileExtensions></configuration></plugin><!--添加配置跳过测试--><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><configuration><skipTests>true</skipTests></configuration></plugin><plugin><groupId>org.graalvm.buildtools</groupId><artifactId>native-maven-plugin</artifactId><configuration><mainClass>com.hollysys.security.authenticate.SecurityServerApplication</mainClass><buildArgs><buildArg>-H:+AddAllCharsets</buildArg><buildArg>--initialize-at-run-time=org.apache.logging.log4j.LogManager</buildArg><buildArg>--initialize-at-run-time=org.apache.logging.log4j.util.ProviderUtil</buildArg><buildArg>--initialize-at-run-time=org.apache.logging.log4j.spi.Provider</buildArg></buildArgs></configuration></plugin></plugins></build><repositories><repository><id>spring-snapshots</id><name>Spring Snapshots</name><url>https://repo.spring.io/snapshot</url><releases><enabled>false</enabled></releases></repository></repositories><pluginRepositories><pluginRepository><id>spring-snapshots</id><name>Spring Snapshots</name><url>https://repo.spring.io/snapshot</url><releases><enabled>false</enabled></releases></pluginRepository></pluginRepositories>

然后先maven install,确保authorize和common都发布到本地mavne仓库,打graalvm包时才能找到

mybatis

参考Mybatis 使用 GraalVM 构建本地映像_mybatis graalvm-CSDN博客

注意MyBatisNativeConfiguration和@MapperScan(basePackages = "com.xxx.mapper", sqlSessionTemplateRef = "sqlSessionTemplate")

mybatis-plus

参考springboot3.2.4+Mybatis-plus在graalvm21环境下打包exe_graalvm打包springboot mybatis plus-CSDN博客

除以上配置外,在reflect-config.json加上

  {"name": "org.apache.ibatis.binding.MapperProxy","methods": [{"name": "<init>", "parameterTypes": ["org.apache.ibatis.session.SqlSession", "java.lang.Class"]}]},

在resource-config.json中加上

 {"pattern": ".*/.*Mapper\\.xml"},

用来扫描Mapper.xml,否则运行mybatis dao层会报错 Invalid bound statement

log4j2

log4j2明确不支持graalvm,把工程中所有带log4j和logging的依赖都删除,包括第三方依赖。只使用

    <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId><version>3.3.10</version><scope>compile</scope></dependency>

其中spring-boot-starter-logging在spring-boot-starter-web中自带。

所有日志注解改为@Slf4j

dsl类没有

虽然工程没用到,但提示java.lang.TypeNotPresentException: Type com.querydsl.core.types.Path not present。

在依赖中添加

<dependency>

<groupId>io.github.openfeign.querydsl</groupId>

<artifactId>querydsl-jpa</artifactId>

<version>6.2.1</version>

<scope>compile</scope>

</dependency>

执行扫描

http://www.xdnf.cn/news/228421.html

相关文章:

  • QT6 源(63)篇六:阅读与注释 QString 这个类,包含了 QString 类的 完整源码,也附上 QLatin1String 类的
  • Redis的简单介绍
  • k8s术语之Replication Controller
  • mmdeploy 转换torch为onnx
  • 2025磐石行动第八周WP
  • JavaScript性能优化实战之代码层面性能优化
  • 贪心算法求解边界最大数
  • 精益数据分析(34/126):深挖电商运营关键要点与指标
  • SAP-ABAP:在SAP系统中,COEP表(成本控制对象行项目表)详解
  • AI 生成UI交互效果
  • 基于C++的IOT网关和平台6:github项目ctGateway后台服务和数据模型
  • C++负载均衡远程调用学习之自定义内存池管理
  • SVTAV1源码-set_all_ref_frame_type
  • 专家访谈:从文本到视频,GEO多模态优化的实战法则
  • IDEA git配置[通俗易懂]
  • halcon打开图形窗口
  • 模型部署技巧(一)
  • Python爬虫实战:获取彼岸网高清素材图片
  • Windows 10 环境二进制方式安装 MySQL 8.0.41
  • Locate 3D:Meta出品自监督学习3D定位方法
  • 大模型——使用 StarRocks 作为向量数据库
  • Go 写一个简单的Get和Post请求服务
  • 03_spring配置优先级
  • 回归分析丨基于R语言复杂数据回归与混合效应模型【多水平/分层/嵌套】技术与代码
  • 数智化招标采购系统针对供应商管理解决方案(采购如何管控供应商)
  • Qt/C++面试【速通笔记六】—Qt 中的线程同步
  • 合并两个有序数组
  • DataWorks Copilot 集成 Qwen3-235B-A22B混合推理模型,AI 效能再升级!
  • uniapp 实现时分秒 分别倒计时
  • 大数据平台与数据仓库的核心差异是什么?