GraalVM原生编译后无法加载JNA依赖问题求助
你的问题是应用在IDE中运行正常,用org.graalvm.buildtools.native插件编译原生镜像也成功,但运行时找不到JNA的原生库,报错如下:
Exception in thread "main" java.lang.UnsatisfiedLinkError: Native library (com/sun/jna/win32-x86-64/jnidispatch.dll) not found in resource path ()
at com.sun.jna.Native.loadNativeDispatchLibraryFromClasspath(Native.java:1059)
at com.sun.jna.Native.loadNativeDispatchLibrary(Native.java:1015)
at com.sun.jna.Native.(Native.java:221)
at com.sun.jna.NativeLong.(NativeLong.java:35)
at java.base@17.0.8/java.lang.Class.ensureInitialized(DynamicHub.java:579)
核心原因是GraalVM原生编译不会自动包含所有资源文件,JNA的平台相关原生库(比如jnidispatch.dll)需要显式配置才能被打包进镜像,同时还要确保反射配置正确。以下是具体解决步骤:
1. 配置Gradle资源包含规则
在你的build.gradle(Groovy DSL)或build.gradle.kts(Kotlin DSL)中添加JNA原生资源的包含规则,确保不同平台的JNA库都被打包:
Groovy DSL 配置
graalvmNative { binaries { main { resources { // 包含所有平台的JNA原生库 includes.add("com/sun/jna/**/*.dll") includes.add("com/sun/jna/**/*.so") includes.add("com/sun/jna/**/*.dylib") } } } }
Kotlin DSL 配置
graalvmNative { binaries { named("main") { resources { includes.addAll(listOf( "com/sun/jna/**/*.dll", "com/sun/jna/**/*.so", "com/sun/jna/**/*.dylib" )) } } } }
2. 配置反射规则(可选但推荐)
JNA的核心类在运行时会用到反射,GraalVM需要提前知道这些类的反射调用信息,否则可能初始化失败。你可以手动添加反射配置,或者用native-image-agent自动生成:
手动添加反射配置
在src/main/resources/META-INF/native-image/目录下创建reflect-config.json,添加以下内容:
[ { "name": "com.sun.jna.Native", "allDeclaredConstructors": true, "allPublicConstructors": true, "allDeclaredMethods": true, "allPublicMethods": true, "allDeclaredFields": true, "allPublicFields": true }, { "name": "com.sun.jna.NativeLong", "allDeclaredConstructors": true, "allPublicConstructors": true, "allDeclaredMethods": true, "allPublicMethods": true } ]
自动生成配置(更准确)
运行IDE中的应用时,添加GraalVM agent参数,让它自动收集所需的反射、资源等配置:
-agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image
运行完成后,agent会在指定目录生成完整的配置文件,覆盖手动配置即可。
3. 确保JNA版本兼容
建议使用支持GraalVM的JNA版本(比如5.13.0及以上),这些版本内置了部分GraalVM适配配置,能减少手动配置的工作量。
验证
执行./gradlew nativeCompile重新编译原生镜像,运行生成的可执行文件,问题应该就能解决。
内容的提问来源于stack exchange,提问作者Tony

