使用Gradle构建jar包运行时抛出java.lang.NoClassDefFoundError异常咨询
问题原因
默认情况下,Gradle原生的jar构建任务不会将任何外部依赖(包含你本地lib目录下的jar包)自动打包到最终构建生成的jar产物中。你编译阶段能正常解析类,是因为Gradle在编译和本地运行测试时会自动维护CompileClassPath和RuntimeClassPath,但是单独执行java -jar启动构建出的jar包时,JVM只会加载当前jar包里的类,不会自动加载外部依赖的类,所以会抛出NoClassDefFoundError异常。
解决方案
有两种常用方案可选:
方案1:构建包含所有依赖的可执行胖Jar
直接在你的build.gradle文件中添加如下配置,修改jar任务的打包逻辑,将所有依赖一并打入最终产物:
jar { manifest { // 此处替换为你自己项目的主类全限定名,示例为你报错中提到的主类 attributes 'Main-Class': 'at.fhv.teamE.communication.Main' } // 将runtime类路径下的所有依赖解压后打入jar包 from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } } // 配置重复文件处理策略,避免打包时重复文件报错 duplicatesStrategy = DuplicatesStrategy.EXCLUDE }
配置完成后重新执行gradle build打包,生成的jar包就可以直接在Ubuntu上使用java -jar 你的jar包名.jar直接运行。
方案2:部署时手动指定类路径
如果你不想把所有依赖打进同一个jar包,可以采用这种方式:
- 把构建生成的项目jar包、存放本地依赖的lib目录都上传到Ubuntu服务器的同一目录下
- 运行时通过
-cp参数指定类路径:
java -cp "你的项目jar包名.jar:lib/* at.fhv.teamE.communication.Main"
注意:Linux系统下类路径分隔符为冒号
:,Windows系统下为分号;,Java 1.6及以上版本支持*通配符直接匹配目录下所有jar包。
不建议配置系统全局的CLASSPATH环境变量,不同项目的依赖版本容易出现冲突,使用运行时指定-cp或者胖Jar的方式更灵活可控。
内容的提问来源于stack exchange,提问作者WackyWollie
相关产品推荐
相关产品推荐

