You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 14:44:09