Maven构建fat jar运行报Log4j2找不到日志实现异常
问题根因
报错是因为fatjar打包过程中log4j2的核心实现类、SPI加载声明文件被破坏或剔除,log4j-api无法识别到存在log4j-core实现,具体触发点有三个:
- 打包插件冲突:pom中同时配置了
maven-assembly-plugin、onejar-maven-plugin、maven-shade-plugin三个fatjar构建插件,package阶段会按插件声明顺序依次执行打包逻辑,最终你运行的jar是最后执行的shade插件产出的,其余两个插件的主类配置、依赖合并规则完全不生效。 - shade插件配置缺陷:
- 开启了
<minimizeJar>true</minimizeJar>自动剔除未引用类的逻辑,log4j-core是通过Java SPI机制被动加载的,shade的静态代码扫描检测不到直接引用,会直接把log4j-core的核心实现类从最终jar里删掉。 - 没有配置SPI服务文件合并、log4j2插件缓存合并的转换器,多个依赖jar包中
META-INF/services路径下的SPI声明文件、log4j2插件配置文件会被互相覆盖,导致log4j-api扫描不到log4j-core的实现入口。
- 开启了
- log4j版本不匹配:引入的log4j-api是官方2.17.0版本,log4j-core是公司定制的
2.17.0-tcs-patch-4版本,版本号不一致会触发log4j的SPI加载校验逻辑,拒绝加载不匹配的core实现。
修复方案
清理冗余打包插件
删除pom中maven-assembly-plugin、onejar-maven-plugin的全部配置,只保留maven-shade-plugin作为fatjar打包工具,避免多插件执行逻辑冲突。maven-jar-plugin是普通薄jar的打包插件,不需要额外配置主类,可保留也可删除,不影响fatjar产出。修正shade插件配置
关闭自动剔除类的开关,补全必需的资源转换器,修正后的配置如下:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.1.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <!-- 关闭自动类剔除,避免误删SPI加载的log4j实现 --> <minimizeJar>false</minimizeJar> <createDependencyReducedPom>true</createDependencyReducedPom> <dependencyReducedPomLocation>${java.io.tmpdir}/dependency-reduced-pom.xml</dependencyReducedPomLocation> <transformers> <!-- 指定jar包启动主类 --> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>XXX.ef.AlertPocDemo</mainClass> </transformer> <!-- 合并所有依赖中META-INF/services下的SPI声明文件,避免覆盖 --> <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> <!-- 合并log4j2的插件缓存文件,保证自定义appender、官方appender能正常加载 --> <transformer implementation="org.apache.maven.plugins.shade.resource.PluginCacheFileTransformer"/> </transformers> <relocations> <relocation> <pattern>com.acme.coyote</pattern> <shadedPattern>hidden.coyote</shadedPattern> </relocation> </relocations> </configuration> </execution> </executions> </plugin>
- 统一log4j版本
将log4j-api的版本调整为和定制版log4j-core完全一致,避免版本校验失败:
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.17.0-tcs-patch-4</version> </dependency>
验证方式
执行mvn clean package重新构建,构建完成后可以先通过命令校验jar包内容是否正常:
- 执行
jar tf target/abc-0.0.1-SNAPSHOT.jar | grep log4j/core/LogManager,能匹配到对应class文件说明log4j-core类没有被剔除 - 执行
jar tf target/abc-0.0.1-SNAPSHOT.jar | grep META-INF/services/org.apache.logging.log4j.spi.Provider,能匹配到文件说明SPI声明存在
之后再执行java -jar target/abc-0.0.1-SNAPSHOT.jar启动,就不会再出现找不到log4j实现的报错。
内容的提问来源于stack exchange,提问作者Jeff Cook
相关产品推荐
相关产品推荐

