命令行运行SmallRye Mutiny的JAR包报NoClassDefFoundError错误
问题现象
通过命令行运行基于SmallRye Mutiny开发的独立应用JAR包时抛出如下错误,IDE内直接运行项目无异常:
Exception in thread "main" java.lang.NoClassDefFoundError: io/smallrye/mutiny/Multi at io.myPage.hello.concat.MultiClass.multiReturn(TestMain.java:25) at io.myPage.hello.concat.TestMain.main(TestMain.java:16) Caused by: java.lang.ClassNotFoundException: io.smallrye.mutiny.Multi at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
对应示例代码如下:
package io.myPage.hello.concat; import io.smallrye.mutiny.Multi; public class TestMain { public static void main(String[] args) { final MultiClass multiClass = new MultiClass(); multiClass.multiReturn().subscribe().with( System.out::println, failure -> System.out.println("Failed with " + failure), () -> System.out.println("Completed")); } } class MultiClass { public Multi<String> multiReturn() { return Multi.createFrom().items("hello", "world", "Batman", "supermain", "london", "köln").onItem().transform(i -> i + "\n"); } }
问题原因
IDE运行项目时会自动将所有声明的第三方依赖(此处为SmallRye Mutiny库)加入运行时类路径,因此可以正常加载依赖类。
你通过构建命令生成的是普通的项目JAR包,包内仅包含自己编写的项目字节码文件,没有把SmallRye Mutiny等第三方依赖的类打包进去。直接通过java -jar运行该JAR时,JVM默认只从当前JAR包内加载类,找不到依赖中的io.smallrye.mutiny.Multi类,就会抛出NoClassDefFoundError。
修复方案
可以根据自己的项目构建工具和使用场景选以下任意一种方案解决:
- 构建包含所有依赖的可执行胖JAR(Fat JAR/Uber JAR)
这是最常用的解决方式,构建出的JAR包含项目代码+所有依赖,可直接通过java -jar命令运行。
如果你使用Maven构建,在pom.xml中添加maven-shade-plugin插件,配置主类入口即可:
配置完成后执行<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.5.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>io.myPage.hello.concat.TestMain</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin>mvn clean package,生成的带依赖后缀的JAR包即可直接运行。
如果你使用Gradle构建,在build.gradle中添加fatJar任务配置:
执行tasks.register('fatJar', Jar) { archiveBaseName = 'mutiny-demo' manifest { attributes 'Main-Class': 'io.myPage.hello.concat.TestMain' } from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } } with jar }./gradlew fatJar(Windows系统执行gradlew.bat fatJar)即可生成带所有依赖的可执行JAR。 - 运行时手动指定依赖类路径
如果不想打包依赖,可以先将所有依赖JAR放到统一目录(比如项目根目录下的lib文件夹),运行JAR时通过-cp参数指定类路径:# Linux/macOS系统 java -cp "your-app.jar:lib/*" io.myPage.hello.concat.TestMain# Windows系统 java -cp "your-app.jar;lib/*" io.myPage.hello.concat.TestMain - 定制运行时镜像(适用于软件分发场景)
Java 9及以上版本可以使用jlink/jpackage工具,将项目代码、依赖、所需JRE模块一起打包为独立运行时镜像,目标机器不需要预装Java环境即可直接运行程序。
内容的提问来源于stack exchange,提问作者BATMAN_2008
相关产品推荐
相关产品推荐

