Maven构建后运行Jar报NoClassDefFoundError: org/slf4j/LoggerFactory
执行mvn clean install构建项目后,运行java -jar target/Sorting-1.0-SNAPSHOT.jar时抛出如下错误:
Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory at xyz.skwar.sorting.Main.<clinit>(Main.java:7) Caused by: java.lang.ClassNotFoundException: org.slf4j.LoggerFactory 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:526) ... 1 more
已尝试以下操作但未解决:
- 引入
logback-classic而非仅SLF4J API - 参考多篇技术文章及Stack Overflow帖子(其中第4个方案无效,第5个场景不符,未设置依赖scope)
- 移除
slf4j-api依赖(按SLF4J文档说明,logback-classic已包含该依赖),但运行出现提示:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
编写最小复现代码仍存在问题:
package xyz.skwar.sorting; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Main { private static final Logger logger = LoggerFactory.getLogger(Main.class); public static void main(String[] args) { logger.info("test"); } }
完整pom.xml文件:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>xyz.skwar.sorting</groupId> <artifactId>Sorting</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>20</maven.compiler.source> <maven.compiler.target>20</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <org.slf4j.version>2.0.9</org.slf4j.version> </properties> <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.30</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>7.8.0</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.4.11</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${org.slf4j.version}</version> </dependency> </dependencies> <pluginRepositories> <pluginRepository> <releases> <updatePolicy>never</updatePolicy> </releases> <snapshots> <enabled>false</enabled> </snapshots> <id>central</id> <name>Central Repository</name> <url>https://repo.maven.apache.org/maven2</url> </pluginRepository> </pluginRepositories> <build> <plugins> <plugin> <!-- Build an executable JAR --> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.1.0</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> <mainClass>xyz.skwar.sorting.Main</mainClass> </manifest> </archive> </configuration> </plugin> </plugins> </build> </project>
核心问题是生成的可执行Jar未包含依赖包:maven-jar-plugin仅打包项目自身代码,不会将SLF4J、Logback等依赖Jar包打包进去,也不会自动把依赖包复制到配置的lib目录下。
以下是两种常用解决方式:
方式一:生成包含所有依赖的Fat Jar(推荐)
使用maven-shade-plugin替换或补充现有插件,它会将所有依赖合并到一个Jar中,直接运行即可:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.4.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>xyz.skwar.sorting.Main</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build>
执行mvn clean package后,直接运行java -jar target/Sorting-1.0-SNAPSHOT.jar即可。
方式二:复制依赖到lib目录并保持原Jar结构
保留原maven-jar-plugin配置,添加maven-dependency-plugin将依赖复制到target/lib目录:
<build> <plugins> <plugin> <!-- 原有的maven-jar-plugin配置 --> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.1.0</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> <mainClass>xyz.skwar.sorting.Main</mainClass> </manifest> </archive> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>3.6.0</version> <executions> <execution> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/lib</outputDirectory> </configuration> </execution> </executions> </plugin> </plugins> </build>
执行mvn clean package后,target目录会生成lib文件夹和原Jar包,直接运行java -jar target/Sorting-1.0-SNAPSHOT.jar即可,Manifest中的classpath会自动指向lib目录下的依赖。
额外说明
logback-classic确实已包含slf4j-api,因此可以移除pom中单独的slf4j-api依赖,避免潜在版本冲突(当前logback-classic 1.4.11依赖的slf4j-api版本为2.0.9,与你配置的版本一致,移除后更简洁)。
内容的提问来源于stack exchange,提问作者benni347

