Kotlin Gradle项目运行Jar时报Ref$ObjectRef类的NoClassDefFoundError
Kotlin可执行Jar运行报NoClassDefFoundError排查与修复
错误现象
执行gradle clean build生成可执行Jar运行时,抛出如下堆栈:
at xyz.colmmurphy.ktop.KtopKt.main(ktop.kt:16) at xyz.colmmurphy.ktop.KtopKt.main(ktop.kt) Caused by: java.lang.ClassNotFoundException: kotlin.jvm.internal.Ref$ObjectRef at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:606) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoader.java:168) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522) ... 2 more
反复核对所有业务实现代码,始终找不到触发异常的对应逻辑。
根因定位
报错找不到的kotlin.jvm.internal.Ref$ObjectRef是Kotlin标准库内置的运行时辅助类,既不是项目自定义的类,也不是第三方依赖提供的类。出现类找不到的问题和业务代码逻辑完全无关,说白了就是打出来的Jar包没有把Kotlin运行时(含kotlin-stdlib、协程运行时等依赖)的字节码打包进最终产物,运行时类加载器扫描不到这些内置类,直接抛错。
这种情况下反复排查业务代码自然没有结果,问题出在Gradle打包配置环节。
常见配置漏洞
出现打漏运行时依赖的场景通常是以下几种:
- 直接使用Gradle默认的Jar任务打包,该任务仅会把项目自身编译生成的类打进去,完全不会附带任何依赖
- 引入了Shadow打包插件但没有正确配置依赖合并规则,导致Kotlin相关依赖被过滤漏掉
- 旧版本Kotlin Gradle插件的兼容Bug,没有正确追踪标准库的类引用
修复操作步骤
- 修改
build.gradle配置,引入Shadow插件生成带全量依赖的可执行Fat Jar:plugins { // Kotlin JVM编译插件 id 'org.jetbrains.kotlin.jvm' // 用于打全量依赖Jar的Shadow插件 id 'com.github.johnrengelman.shadow' version '8.1.1' application } application { // 指定项目主类 mainClass.set('xyz.colmmurphy.ktop.KtopKt') } - 配置ShadowJar任务的Manifest信息,确保Jar入口正确:
tasks.named('shadowJar') { archiveBaseName.set('ktop') archiveVersion.set('1.0.0') manifest { attributes 'Main-Class': 'xyz.colmmurphy.ktop.KtopKt' } // 合并依赖中的服务文件,避免协程等库的配置被覆盖 mergeServiceFiles() } - 执行打包命令生成最终产物,不要使用默认
build任务生成的薄Jar:gradle clean shadowJar - 运行
build/libs目录下带all后缀的Jar包,即可正常启动,不会再报找不到Kotlin内置类的错误。
附带的代码逻辑隐患
这类打包问题修复后运行代码还可能踩到其他坑,提前调整可以避免后续报错:
- 代码中通过
GlobalScope.launch给lateinit变量赋值的逻辑,目前靠Thread.sleep(6000)硬等协程执行完成的方式不可靠,如果协程执行延迟超过等待时间,读取未初始化的lateinit变量会直接抛UninitializedPropertyAccessException CPUCore类的infoList属性实现冗余:构造时传入了从/proc/stat读取的行字符串,但每次取值都会重新全量读取/proc/stat文件,既拖慢性能,也和构造函数传入的参数逻辑割裂readCPUUsage方法操作文件输入流时没有用use块自动关闭资源,长时间运行会导致文件句柄泄漏
内容的提问来源于stack exchange,提问作者colmmurphyxyz
相关产品推荐
相关产品推荐

