SpringBoot3构建GraalVM NativeImage

1,261 阅读20分钟

由于GraalVM使用的是静态分析生成本地镜像,所以我们如果直接执行gradlew nativeRun,一般会比较容易出错,没写什么代码还好,写了代码之后加上一堆第三方库,就目前来说,报错是必然的,总有一些第三方库调用奇怪的反射,动态代理之类的,所以这时候我们就需要借助GraalVM的agent来生成元数据,再利用生成的元数据去生成本地镜像,不过这就有一个缺点,就是我们尽量要做到运行之后,代码100%覆盖,这就比较要命了,不过还是本着先试的原则,跑一下再说(文章有错误或不合适的地方可以联系我)

(一)初始化GraalVM的环境

1.下载官网的GraalVM,这个其实跟jdk差不多,我用的是Windows
GraalVM 22.3.2社区版jdk17下载地址: github.com/graalvm/gra…

下载完以后将bin文件夹加入到环境变量

#初次使用,先安装native-image(后面生成镜像要用到这个命令)
D:\graalvm-ce-java17-22.3.2\bin> gu install native-image

#检查是否安装成功,出现native-image表示安装成功
D:\graalvm-ce-java17-22.3.2\bin> gu list

ComponentId              Version             Component name                Stability                     Origin
---------------------------------------------------------------------------------------------------------------------------------
graalvm                  22.3.2              GraalVM Core                  Supported
native-image             22.3.2              Native Image                  Early adopter                 github.com

2.在Windows的话,我们需要下载Visual Studio2019,GraalVM会根据Visual Studio去生成适合Windows的镜像,在这里,我引用一下我参考的一篇文章,大家有需要的话可以看下原文medium.com/graalvm/usi…

(1)Visual Studio2019下载地址:visualstudio.microsoft.com/zh-hans/vs/…
(2)安装的开发组件选择这几个(Win11的电脑不一定要选win11的sdk,10就足够了)

image.png 在Individual Components(单个组件)将Visual Studio Sdk也勾上,点Install就好

image.png 安装好以后我们会在开始菜单中得到一个x64 Native Tools Command Prompt for VS 2019(也就vcvars64.bat),我们之后需要在这个终端里面执行命令生成本地镜像

image.png

(二)收集编译需要的数据

由于我的项目用到了Netty,ProtoBuf,Log4j一些组件,他们内部存在了反射,我需要针对他们的反射去做一些配置,不然编译不通过,编译通过运行也会出现找不到方法或者空指针的异常,如果你只用了SpringBoot创建项目默认的代码,你可以直接跳过这个大步骤,因为SpringBoot对于自己的组件已经配置好元数据了,在不添加第三方依赖的情况下应该可以直接编译

1.收集程序元数据

//1.在idea或用gradle先生成jar包
D:\your_projects> gradlew bootJar
//2.得到jar包之后,执行命令运行并开始收集元数据
D:\your_projects\jarPath> java -jar -agentlib:native-image-agent=config-output-dir=META-INF/native-image your_xxxx.jar
/**
  * 接着程序就开始运行了,我们可能需要打开网页或者测试工具将所有代码都跑完,这个是最蛋疼的,
  * 跑不完生成的镜像可能也可以运行,但指不定你哪天就报错了,或者运行到某一块有特别反射的地方
  * 也报错,就尴尬了
  * /
//3.收集完以后按Ctrl+C结束运行才会得到文件,我们会在当前目录的META-INF/native-image中得到的数据,接着就用
//这些收集到的数据开始生成本地镜像

2.将收集到的META-INF放入到SpringBoot的resources目录下

其中reflect-config.json是反射配置,算是比较主要的,个人试错经验,如果一次性把META-INF放进去编译报错的话,建议native编译报错什么再加什么配置(如果非SpringBoot项目,能让META-INF打包进jar包就行)

aaaa.png

(三)生成本地镜像

打开x64 Native Tools Command Prompt for VS 2019

(1)使用Gradle命令(推荐)

使用gradle需要我们在gradle中加入graalvm的插件

your_project/build.gradle
plugins {  
    id 'java'  
    id 'org.springframework.boot' version '3.1.0'  
    id 'io.spring.dependency-management' version '1.1.0' 
    
    /************************Add************************/
    id 'org.graalvm.buildtools.native' version '0.9.20'  
    /**********************Add End**********************/
}


/**************************Add**********************************/
//原生构建参数  
graalvmNative {  
    binaries {  
        main {
            //指定程序的主函数入口,SpringBoot可以不用写
            //mainClass = 'mscript.MScriptApplication'
            //自动检测资源  
            resources.autodetect()  
            //--initialize-at-build-time修复Log4j无法找到的问题,如果编的时候有其它Class找不到,但正常运行jar包又没问题,可以尝试把报错  
            //的Class加到这里,多个Class用逗号分隔,-H:+ReportExceptionStackTraces表示出错了打印堆栈  
            buildArgs[  
            "--initialize-at-build-time=org.slf4j.LoggerFactory" +  
            ",ch.qos.logback.classic.Logger" +  
            ",ch.qos.logback.core.status.InfoStatus" +  
            ",ch.qos.logback.classic.Level" +  
            ",ch.qos.logback.core.util.Loader" +  
            ",ch.qos.logback.core.util.StatusPrinter",  
            "--trace-object-instantiation=java.util.jar.JarFile",  
            "-H:+ReportExceptionStackTraces",  
            ]  
            //关闭工具链检测,减少不必要的检测  
            toolchainDetection = false  
        }  
    }  
}
/**************************Add End**********************************/
#编译,编译直接可以得到原生镜像
D:\your_projects>gradlew nativeCompile
#运行,也可以直接运行,运行会自动编译
D:\your_projects>gradlew nativeRun

###########编译好的结果会放到build/native/nativeCompile目录,到这里就可以正常使用了############

(2)使用native-image命令生成镜像(不建议)

这种方式仅仅适合编译一些没有什么依赖的jar,如果编译依赖太多的项目,构建参数太长了,最好还是用插件吧
#-cp把所有用到的依赖全部加进来,包括自己当前的jar和间接引用的jar
native-image -cp your_xxx.jar -jar your_xxx.jar

#上面只是方便理解的简写(仅仅适用于那种没什么依赖java代码),实际上Gradle完整构建生成的参数
-cp E:\\MelProjects\\your_project\\build\\libs\\your_project-1.0-SNAPSHOT-plain.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.springframework.boot\\spring-boot-starter-web\\3.0.4\\6a7405b436c6943f056cdbab587fe48bdc2b4911\\spring-boot-starter-web-3.0.4.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.springframework.boot\\spring-boot-starter-jdbc\\3.0.4\\e64f229f772dc2952e1978a1f10d7f3a462e105d\\spring-boot-starter-jdbc-3.0.4.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.grpc\\grpc-protobuf\\1.53.0\\41f37de10ef5e4a30cbb9ef89405b864b9342f5e\\grpc-protobuf-1.53.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.grpc\\grpc-stub\\1.53.0\\391663182785fdb6f92486f432e927cff60c6bcf\\grpc-stub-1.53.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\com.qmel\\qrtpserver\\1.0.0-dev60\\a162f8ebf686ed30935aef4175e47754401a3a4a\\qrtpserver-1.0.0-dev60.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.xerial\\sqlite-jdbc\\3.40.1.0\\4e77207cd5a1c3ee00e287b7792683463dc50570\\sqlite-jdbc-3.40.1.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.mariadb.jdbc\\mariadb-java-client\\3.1.2\\801ace72b17a40da0bfa8c37e4e09ea4fce68284\\mariadb-java-client-3.1.2.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.springframework\\spring-jdbc\\6.0.6\\151e730f45832d42c6535b0bc6d7cebeabcaf844\\spring-jdbc-6.0.6.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.springdoc\\springdoc-openapi-ui\\1.6.15\\be2b096e2f5486e562e99cb7b78af4691d10655c\\springdoc-openapi-ui-1.6.15.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.grpc\\grpc-netty-shaded\\1.53.0\\e302201caf3289e8a030b111d90fed64108b5957\\grpc-netty-shaded-1.53.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.springframework.boot\\spring-boot-starter-json\\3.1.0\\546bd372bc070339c4255ed37f4f0ff5aafa2648\\spring-boot-starter-json-3.1.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.springframework.boot\\spring-boot-starter\\3.1.0\\2960a1f899f4ee3eb815dc85986b0428c1a5289f\\spring-boot-starter-3.1.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.springframework.boot\\spring-boot-starter-tomcat\\3.1.0\\e7ea53de5a58aaf63f0e3a80d438f7dfc0b9806b\\spring-boot-starter-tomcat-3.1.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.springdoc\\springdoc-openapi-webmvc-core\\1.6.15\\1a90cef11f8139bbc49ff5207388d828be0fd4c6\\springdoc-openapi-webmvc-core-1.6.15.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.springframework\\spring-webmvc\\6.0.9\\e127c07a23403832d0c6292f4a0bf8c7a2b7329f\\spring-webmvc-6.0.9.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.springdoc\\springdoc-openapi-common\\1.6.15\\d671e27d97c86235f355016c0c99d8a1cf3694d5\\springdoc-openapi-common-1.6.15.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.springframework\\spring-web\\6.0.9\\2837dec8a75ecfdad367d6c30ce9cbdfc89caa7a\\spring-web-6.0.9.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\com.zaxxer\\HikariCP\\5.0.1\\a74c7f0a37046846e88d54f7cb6ea6d565c65f9c\\HikariCP-5.0.1.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.grpc\\grpc-protobuf-lite\\1.53.0\\e54a4ff36048a5a28d033791187b985dc5abbe73\\grpc-protobuf-lite-1.53.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.grpc\\grpc-core\\1.53.0\\be781334b80a78f11044813fba123826d2df4b6b\\grpc-core-1.53.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.grpc\\grpc-api\\1.53.0\\968fdbb4369cbf03302b1137e52e97c4d49bd548\\grpc-api-1.53.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\com.google.guava\\guava\\31.1-android\\9222c47cc3ae890f07f7c961bbb3cb69050fe4aa\\guava-31.1-android.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\com.google.code.findbugs\\jsr305\\3.0.2\\25ea2e8b0c338a877313bd4672d3fe056ea78f0d\\jsr305-3.0.2.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\com.google.api.grpc\\proto-google-common-protos\\2.9.0\\e4ada41aaaf6ecdedf132f44251d0d50813f7f90\\proto-google-common-protos-2.9.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\com.google.protobuf\\protobuf-java\\3.21.9\\ed1240d9231044ce6ccf1978512f6e44416bb7e7\\protobuf-java-3.21.9.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\com.github.waffle\\waffle-jna\\3.2.0\\6ac5882dea3a15575237ef5d1793c51279ae1335\\waffle-jna-3.2.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\com.github.ben-manes.caffeine\\caffeine\\3.1.6\\3646a0d1b1abe6a31f72f2237d9004d10a5be91d\\caffeine-3.1.6.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\com.google.errorprone\\error_prone_annotations\\2.18.0\\89b684257096f548fa39a7df9fdaa409d4d4df91\\error_prone_annotations-2.18.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.springframework\\spring-tx\\6.0.9\\89818f4cc656107709d3db6b238ed9b776d3dbb4\\spring-tx-6.0.9.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.springframework.boot\\spring-boot-autoconfigure\\3.1.0\\b06d1f0b08f6f8a2636e364c8941b2dabc4f0b77\\spring-boot-autoconfigure-3.1.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.springframework.boot\\spring-boot\\3.1.0\\efa941e9a2162a3dd8c5e4679f46a24af9e5769f\\spring-boot-3.1.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.springframework\\spring-context\\6.0.9\\be88c57829b9ec038774b47c241ac45673352a55\\spring-context-6.0.9.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.springframework\\spring-aop\\6.0.9\\8c1025bf9c1dc66f5268639866b5a45ed9bc62ef\\spring-aop-6.0.9.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.springframework\\spring-beans\\6.0.9\\745619eee32c8ead88a21c97748d2416f1db8dd9\\spring-beans-6.0.9.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.springframework\\spring-expression\\6.0.9\\f50a1df7ed038ee7ca85528aff652cef4ff4883b\\spring-expression-6.0.9.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.springframework\\spring-core\\6.0.9\\284ed111fa0b49b29f6fea6ac0afa402b809e427\\spring-core-6.0.9.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.webjars\\swagger-ui\\4.17.1\\b782c736990e484a00223b6e4204119ce3770c8c\\swagger-ui-4.17.1.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.webjars\\webjars-locator-core\\0.52\\f219134c6b8d4aebfea70f135b2f80dc2794253f\\webjars-locator-core-0.52.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.github.classgraph\\classgraph\\4.8.149\\4bc2f188bc9001473d4a26ac488c2ae1a3e906de\\classgraph-4.8.149.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-all\\4.1.92.Final\\3af6c651f6fdd1d7ed49a27ad59397c75af3d278\\netty-all-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\com.google.code.gson\\gson\\2.10.1\\b3add478d4382b78ea20b1671390a858002feb6c\\gson-2.10.1.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.perfmark\\perfmark-api\\0.25.0\\340a0c3d81cdcd9ecd7dc2ae00fb2633b469b157\\perfmark-api-0.25.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.springframework.boot\\spring-boot-starter-logging\\3.1.0\\4784b6e2adfe32720a4e2c009a62650835bba391\\spring-boot-starter-logging-3.1.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\jakarta.annotation\\jakarta.annotation-api\\2.1.1\\48b9bda22b091b1f48b13af03fe36db3be6e1ae3\\jakarta.annotation-api-2.1.1.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.swagger.core.v3\\swagger-core\\2.2.8\\c97d0e6f14d0122f42f47ead589e6b9c07c6c1b3\\swagger-core-2.2.8.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\com.fasterxml.jackson.datatype\\jackson-datatype-jdk8\\2.15.0\\ddfd375d4df3a4c149bf7d5d71c45b91909cf31f\\jackson-datatype-jdk8-2.15.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\com.fasterxml.jackson.datatype\\jackson-datatype-jsr310\\2.15.0\\3c3a0cfba09271fab4603224f2c2e21c6ddf6dc4\\jackson-datatype-jsr310-2.15.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\com.fasterxml.jackson.module\\jackson-module-parameter-names\\2.15.0\\b900bd44597ba9a8b348b49428f457d5f16fc302\\jackson-module-parameter-names-2.15.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\com.fasterxml.jackson.core\\jackson-databind\\2.15.0\\d41caa3a4e9f85382702a059a65c512f85ac230\\jackson-databind-2.15.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\com.fasterxml.jackson.core\\jackson-core\\2.15.0\\12f334a1dc9c6d2854c43ae314024dde8b3ad572\\jackson-core-2.15.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.swagger.core.v3\\swagger-models\\2.2.8\\2a9cee980d3c7c9545db1438cdb4691f166e6954\\swagger-models-2.2.8.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\com.fasterxml.jackson.core\\jackson-annotations\\2.15.0\\89b0fd554928425a776a6e97ed010034312af21d\\jackson-annotations-2.15.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\com.fasterxml.jackson.dataformat\\jackson-dataformat-yaml\\2.15.0\\fafaf40ed4bcd4bc29891441b7d256f24e55fa7f\\jackson-dataformat-yaml-2.15.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.yaml\\snakeyaml\\1.33\\2cd0a87ff7df953f810c344bdf2fe3340b954c69\\snakeyaml-1.33.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.apache.tomcat.embed\\tomcat-embed-websocket\\10.1.8\\7abb8ab966dd135924c8e69cb2f1db735dee5f23\\tomcat-embed-websocket-10.1.8.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.apache.tomcat.embed\\tomcat-embed-core\\10.1.8\\ec4b884806c65c80c86bb3db134f6f6f99e79ed8\\tomcat-embed-core-10.1.8.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.apache.tomcat.embed\\tomcat-embed-el\\10.1.8\\6f3a4ae2ae37270eeb6e9bec4e7207facdc9e8fa\\tomcat-embed-el-10.1.8.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.micrometer\\micrometer-observation\\1.11.0\\b3d1b34d16e7e8fa9087c5d51ec39bc3005e2733\\micrometer-observation-1.11.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.slf4j\\jcl-over-slf4j\\2.0.7\\f127fe5ee53404a8b3697cdd032dd1dd6a29dd77\\jcl-over-slf4j-2.0.7.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\ch.qos.logback\\logback-classic\\1.4.7\\307944865579a6d490e6a4cbb5082dc8f36536ca\\logback-classic-1.4.7.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.apache.logging.log4j\\log4j-to-slf4j\\2.20.0\\d37f81f8978e2672bc32c82712ab4b3f66624adc\\log4j-to-slf4j-2.20.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.slf4j\\jul-to-slf4j\\2.0.7\\a48f44aeaa8a5ddc347007298a28173ac1fbbd8b\\jul-to-slf4j-2.0.7.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.slf4j\\slf4j-api\\2.0.7\\41eb7184ea9d556f23e18b5cb99cad1f8581fc00\\slf4j-api-2.0.7.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.grpc\\grpc-context\\1.53.0\\70aa77c3e715b6f22a42c466eb2f48031bc468fb\\grpc-context-1.53.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\com.google.guava\\failureaccess\\1.0.1\\1dcf1de382a0bf95a3d8b0849546c88bac1292c9\\failureaccess-1.0.1.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\com.google.guava\\listenablefuture\\9999.0-empty-to-avoid-conflict-with-guava\\b421526c5f297295adef1c886e5246c39d4ac629\\listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.checkerframework\\checker-qual\\3.33.0\\de2b60b62da487644fc11f734e73c8b0b431238f\\checker-qual-3.33.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\com.google.j2objc\\j2objc-annotations\\1.3\\ba035118bc8bac37d7eff77700720999acd9986d\\j2objc-annotations-1.3.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\net.java.dev.jna\\jna-platform\\5.12.1\\97406a297c852f4a41e688a176ec675f72e8329\\jna-platform-5.12.1.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\net.java.dev.jna\\jna\\5.12.1\\b1e93a735caea94f503e95e6fe79bf9cdc1e985d\\jna-5.12.1.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.springframework\\spring-jcl\\6.0.9\\88d9ddfc6bbbf4047c2a8de8de94a425b06f636a\\spring-jcl-6.0.9.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-transport-native-epoll\\4.1.92.Final\\287cddec8463544c7a5c79dfd2fafc6058baef9\\netty-transport-native-epoll-4.1.92.Final-linux-x86_64.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-transport-native-epoll\\4.1.92.Final\\725ff7c76eb5e8e33380c246e7ce1f9c5ac10c58\\netty-transport-native-epoll-4.1.92.Final-linux-aarch_64.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-transport-native-kqueue\\4.1.92.Final\\e6547a23ac082b58db1fa061ff0d1f52f672ca30\\netty-transport-native-kqueue-4.1.92.Final-osx-x86_64.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-transport-native-kqueue\\4.1.92.Final\\58385d4a06aa2527a68b332519f2b02cb626bd63\\netty-transport-native-kqueue-4.1.92.Final-osx-aarch_64.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-transport-classes-epoll\\4.1.92.Final\\ca149d6a9a028eafcd6b45e3884529d04628fe64\\netty-transport-classes-epoll-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-transport-classes-kqueue\\4.1.92.Final\\eba77dc5bf182acff1db9cef44c423f60aae3468\\netty-transport-classes-kqueue-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-resolver-dns-native-macos\\4.1.92.Final\\b3b38c2c4a226cbe5a0013c05bcf704ee025c67b\\netty-resolver-dns-native-macos-4.1.92.Final-osx-x86_64.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-resolver-dns-native-macos\\4.1.92.Final\\d98d3c6285d6dccfdf8d976bcee2b889e0d7e13e\\netty-resolver-dns-native-macos-4.1.92.Final-osx-aarch_64.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-resolver-dns-classes-macos\\4.1.92.Final\\ea1bee2e2356c7d9cb8c31325486884dd6b84994\\netty-resolver-dns-classes-macos-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-resolver-dns\\4.1.92.Final\\31ade4afd046a1701d420aac3c2eb6ffc25f87b5\\netty-resolver-dns-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-handler\\4.1.92.Final\\d8e961d89a966c0cdea88105bbb2353408a41d12\\netty-handler-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-transport-native-unix-common\\4.1.92.Final\\22364cca56b752abb49fb7972f0f6299b8d6be98\\netty-transport-native-unix-common-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-codec-dns\\4.1.92.Final\\1416eb862edf16d0e5e867d47b4f00937e7133ee\\netty-codec-dns-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-codec\\4.1.92.Final\\9496b3d59290edcc6480cbe064f33560873f7484\\netty-codec-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-transport\\4.1.92.Final\\e0cf483b7c04af7207c02a6ff0c861592b09c97a\\netty-transport-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-buffer\\4.1.92.Final\\5ff1ba7ec68c20e635fc0f2b792c38c951f688d6\\netty-buffer-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-codec-haproxy\\4.1.92.Final\\e3980ed823c6600d5bc2d1bd138278a2cde2e2f7\\netty-codec-haproxy-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-codec-http\\4.1.92.Final\\b91f907a19c6bfb318077951eb28a3dbee8f41fd\\netty-codec-http-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-codec-http2\\4.1.92.Final\\65afd3b26bf167c6e31fa179933fd437a64d0b5f\\netty-codec-http2-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-codec-memcache\\4.1.92.Final\\2e0a98107ce3ecdaf296248523c1b01e212a43a9\\netty-codec-memcache-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-codec-mqtt\\4.1.92.Final\\c4d2b8af5067da852d2c75f21b9bbef3415c4662\\netty-codec-mqtt-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-codec-redis\\4.1.92.Final\\e44304d44353d9601788021151ca6ab3f031ce5b\\netty-codec-redis-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-codec-smtp\\4.1.92.Final\\352a7f80f6a1405b29d290cd12821f44c9fd4111\\netty-codec-smtp-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-codec-socks\\4.1.92.Final\\ae1daa774f14a4cd9ce87465018ca961357ee8d3\\netty-codec-socks-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-codec-stomp\\4.1.92.Final\\a5b3656c9a3de01437fcfea7042111ef1c4fb8d0\\netty-codec-stomp-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-codec-xml\\4.1.92.Final\\55dbb3266fb85e38b5b9449e79aaf6bf02a5f168\\netty-codec-xml-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-resolver\\4.1.92.Final\\fe96e210a4e139cb043d26702792b6098b93b13f\\netty-resolver-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-common\\4.1.92.Final\\66133f9ad31816a227acf3030632903cb9e4c5a2\\netty-common-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-handler-proxy\\4.1.92.Final\\d29ed946518e608e7e18225ee05a23c77c2dee82\\netty-handler-proxy-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-handler-ssl-ocsp\\4.1.92.Final\\63a3f526abdc3acc652b5e908df41888f55b74f3\\netty-handler-ssl-ocsp-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-transport-rxtx\\4.1.92.Final\\a67b974dc9bcd92d06e939485a068c62403bda1c\\netty-transport-rxtx-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-transport-sctp\\4.1.92.Final\\e566b0ef159adabc68e95573ab6d60c990b74373\\netty-transport-sctp-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.netty\\netty-transport-udt\\4.1.92.Final\\b32c7928f40a90fbea067552703f888ec052555e\\netty-transport-udt-4.1.92.Final.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\com.google.android\\annotations\\4.1.1.4\\a1678ba907bf92691d879fef34e1a187038f9259\\annotations-4.1.1.4.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.codehaus.mojo\\animal-sniffer-annotations\\1.21\\419a9acd297cb6fe6f91b982d909f2c20e9fa5c0\\animal-sniffer-annotations-1.21.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.micrometer\\micrometer-commons\\1.11.0\\5de5da6be4f01128ab3995acdf86f2844137d4e4\\micrometer-commons-1.11.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\ch.randelshofer\\fastdoubleparser\\0.8.0\\85c25540369921659556ead85e02c99ef0d24280\\fastdoubleparser-0.8.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\ch.qos.logback\\logback-core\\1.4.7\\a2948dae4013d0e9486141b4d638d8951becb767\\logback-core-1.4.7.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.apache.logging.log4j\\log4j-api\\2.20.0\\1fe6082e660daf07c689a89c94dc0f49c26b44bb\\log4j-api-2.20.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\jakarta.xml.bind\\jakarta.xml.bind-api\\4.0.0\\bbb399208d288b15ec101fa4fcfc4bd77cedc97a\\jakarta.xml.bind-api-4.0.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\org.apache.commons\\commons-lang3\\3.12.0\\c6842c86792ff03b9f1d1fe2aab8dc23aa6c6f0e\\commons-lang3-3.12.0.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\io.swagger.core.v3\\swagger-annotations\\2.2.8\\6b14c60519512cd627d59423f109949bea203727\\swagger-annotations-2.2.8.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\jakarta.validation\\jakarta.validation-api\\3.0.2\\92b6631659ba35ca09e44874d3eb936edfeee532\\jakarta.validation-api-3.0.2.jar;C:\\Users\\Administrator\\.gradle\\caches\\modules-2\\files-2.1\\jakarta.activation\\jakarta.activation-api\\2.1.2\\640c0d5aff45dbff1e1a1bc09673ff3a02b1ba12\\jakarta.activation-api-2.1.2.jar;E:\\MelProjects\\your_project\\build\\classes\\java\\aot;E:\\MelProjects\\your_project\\build\\resources\\aot;E:\\MelProjects\\your_project\\build\\generated\\aotClasses
 --no-fallback
 -H:Path=E:\\MelProjects\\your_project\\build\\native\\nativeCompile
 -H:Name=your_project
 -H:ConfigurationFileDirectories=E:\\MelProjects\\your_project\\build\\native\\generated\\generateResourcesConfigFile,C:\\Users\\Administrator\\.gradle\\native-build-tools\\repositories\\65922baf11b81003e6b6e70f3aa4dfd71295c9a3\\exploded\\ch.qos.logback\\logback-classic\\1.4.1,C:\\Users\\Administrator\\.gradle\\native-build-tools\\repositories\\65922baf11b81003e6b6e70f3aa4dfd71295c9a3\\exploded\\org.apache.tomcat.embed\\tomcat-embed-core\\10.0.20,C:\\Users\\Administrator\\.gradle\\native-build-tools\\repositories\\65922baf11b81003e6b6e70f3aa4dfd71295c9a3\\exploded\\com.zaxxer\\HikariCP\\5.0.1,C:\\Users\\Administrator\\.gradle\\native-build-tools\\repositories\\65922baf11b81003e6b6e70f3aa4dfd71295c9a3\\exploded\\org.mariadb.jdbc\\mariadb-java-client\\3.0.6,C:\\Users\\Administrator\\.gradle\\native-build-tools\\repositories\\65922baf11b81003e6b6e70f3aa4dfd71295c9a3\\exploded\\net.java.dev.jna\\jna\\5.8.0,C:\\Users\\Administrator\\.gradle\\native-build-tools\\repositories\\65922baf11b81003e6b6e70f3aa4dfd71295c9a3\\exploded\\com.github.ben-manes.caffeine\\caffeine\\3.1.2,C:\\Users\\Administrator\\.gradle\\native-build-tools\\repositories\\65922baf11b81003e6b6e70f3aa4dfd71295c9a3\\exploded\\io.netty\\netty-buffer\\4.1.80.Final,C:\\Users\\Administrator\\.gradle\\native-build-tools\\repositories\\65922baf11b81003e6b6e70f3aa4dfd71295c9a3\\exploded\\io.netty\\netty-common\\4.1.80.Final,C:\\Users\\Administrator\\.gradle\\native-build-tools\\repositories\\65922baf11b81003e6b6e70f3aa4dfd71295c9a3\\exploded\\io.netty\\netty-transport\\4.1.80.Final,C:\\Users\\Administrator\\.gradle\\native-build-tools\\repositories\\65922baf11b81003e6b6e70f3aa4dfd71295c9a3\\exploded\\io.netty\\netty-codec-http\\4.1.80.Final,C:\\Users\\Administrator\\.gradle\\native-build-tools\\repositories\\65922baf11b81003e6b6e70f3aa4dfd71295c9a3\\exploded\\io.netty\\netty-codec-http2\\4.1.80.Final,C:\\Users\\Administrator\\.gradle\\native-build-tools\\repositories\\65922baf11b81003e6b6e70f3aa4dfd71295c9a3\\exploded\\io.netty\\netty-handler\\4.1.80.Final,C:\\Users\\Administrator\\.gradle\\native-build-tools\\repositories\\65922baf11b81003e6b6e70f3aa4dfd71295c9a3\\exploded\\io.netty\\netty-resolver-dns\\4.1.80.Final
 --initialize-at-build-time=org.slf4j.LoggerFactory,ch.qos.logback.classic.Logger,ch.qos.logback.core.status.InfoStatus,ch.qos.logback.classic.Level,ch.qos.logback.core.util.Loader,ch.qos.logback.core.util.StatusPrinter
 --trace-object-instantiation=java.util.jar.JarFile
 -H:+ReportExceptionStackTraces
 

(四)运行测试

(1)双击exe执行结果(113MB)

image.png

(2)java -jar执行结果(体积62.7MB)

image.png

同一应用启动速度从2.21s降到0.162s,启动速度因为少了jvm以及本地化的原因,确实提高了很多,不过主要还得看实际性能,实际运行性能和内存占用有待测试

以上是Windows教程,经过测试,如果Windows编译没问题,Ubuntu的话配置好GraalVM环境变量,直接执行gradlew nativeCompile基本可以直接得到Linux二进制文件