SBT构建项目添加Apache Zookeeper 3.7.0依赖后出现重复类文件错误的解决方法
解决SBT Assembly中ZooKeeper依赖引发的log4j重复类错误
问题描述
我在子模块中引入ZooKeeper 3.7.0依赖后,执行SBT构建时遭遇大量重复类错误,核心报错如下:
[error] (assembly) deduplicate: different file contents found in the following: [error] C:\Users\****\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\org\slf4j\log4j-over-slf4j\1.7.25\log4j-over-slf4j-1.7.25.jar:org/apache/log4j/Appender.class [error] C:\Users\****\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\log4j\log4j\1.2.17\log4j-1.2.17.jar:org/apache/log4j/Appender.class [error] deduplicate: different file contents found in the following: [error] C:\Users\****\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\org\slf4j\log4j-over-slf4j\1.7.25\log4j-over-slf4j-1.7.25.jar:org/apache/log4j/AppenderSkeleton.class [error] C:\Users\****\AppData\Local\Coursier\cache\v1\https\repo1.maven.org\maven2\log4j\log4j\1.2.17\log4j-1.2.17.jar:org/apache/log4j/AppenderSkeleton.class
我尝试过排除冲突依赖:
"org.apache.zookeeper" % "zookeeper" % "3.7.0" exclude("org.slf4j", "slf4j-log4j12") exclude("log4j", "log4j")
但问题仍未解决,请问该如何修复?
问题根源
这是典型的日志依赖冲突:log4j-over-slf4j(SLF4J到log4j的桥接器)和原生log4j包包含了完全相同路径的类,但类内容不一致。SBT Assembly插件在打包时严格检查重复类,因此抛出错误。你之前的排除操作只针对ZooKeeper自身的依赖,但项目中可能还有其他依赖间接引入了这两个冲突包。
修复方案
方案1:全局排除冲突依赖,统一日志体系
推荐保留log4j-over-slf4j(适配SLF4J日志标准),全局排除所有log4j的直接/间接依赖,同时确保ZooKeeper的依赖排除覆盖全面:
// 全局排除log4j,避免任何依赖引入它 excludeDependencies += "log4j" % "log4j" // 调整ZooKeeper依赖的排除规则,覆盖所有相关冲突 libraryDependencies += "org.apache.zookeeper" % "zookeeper" % "3.7.0" excludeAll( ExclusionRule("log4j", "log4j"), ExclusionRule("org.slf4j", "slf4j-log4j12") ) // 记得添加你项目使用的SLF4J实现,比如Logback libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.2.10"
方案2:配置Assembly的合并策略处理重复类
如果无法完全排除其中一个包(比如某些老依赖必须用原生log4j),可以让Assembly插件遇到重复类时保留指定版本:
assemblyMergeStrategy in assembly := { // 对于org.apache.log4j下的所有类,保留第一个找到的版本 case PathList("org", "apache", "log4j", _*) => MergeStrategy.first // 其他类使用默认的合并策略 case other => val defaultStrategy = (assemblyMergeStrategy in assembly).value defaultStrategy(other) }
这个配置会告诉Assembly遇到log4j包下的重复类时,优先保留依赖树中先加载的那个版本。
方案3:使用ZooKeeper的精简依赖版本
ZooKeeper的官方依赖包含了多种日志桥接器,你可以直接排除所有日志相关依赖,然后手动添加项目需要的日志框架:
libraryDependencies += "org.apache.zookeeper" % "zookeeper" % "3.7.0" excludeAll( ExclusionRule(organization = "org.slf4j"), ExclusionRule(organization = "log4j"), ExclusionRule(organization = "commons-logging") ) // 手动添加SLF4J API和实现 libraryDependencies += "org.slf4j" % "slf4j-api" % "1.7.36" libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.2.10"
验证方法
执行sbt dependencyTree命令查看项目的依赖树,确认log4j和log4j-over-slf4j是否不再同时出现,之后再运行sbt assembly验证打包是否成功。
内容的提问来源于stack exchange,提问作者 iluxa1810
相关产品推荐
相关产品推荐

