如何从sbt发布的jar包中排除logback-classic日志传递依赖
Scala类库SLF4J依赖配置最优方案
不要使用全局exclude()处理logback依赖,该方式无法同时满足本地开发日志输出、发布不传递绑定依赖、assembly打包内置实现三个核心需求,按以下步骤配置即可完全符合SLF4J官方规范:
基础依赖配置
在build.sbt中按作用域声明依赖:
slf4j-api作为常规编译依赖,随构件对外传递,符合类库依赖要求logback-classic声明为Provided作用域,该作用域的依赖在本地sbt runMain、testOnly、IntelliJ运行/调试场景下会自动加入类路径,可正常输出日志;同时发布构件生成的pom文件中,该依赖为provided范围,不会作为传递依赖被下游用户拉取,不会强制用户使用指定日志实现
libraryDependencies ++= Seq( "org.slf4j" % "slf4j-api" % "2.0.9", "ch.qos.logback" % "logback-classic" % "1.4.11" % Provided )
注意:不要将logback-classic放在Test作用域下,该作用域的依赖仅在测试阶段可用,
sbt runMain启动应用时类路径中无日志实现,会出现SLF4J无绑定的警告,无法输出日志。
sbt-assembly打包适配
sbt-assembly插件默认会排除Provided作用域的依赖,因此添加以下配置,定向将logback相关依赖加入fat jar,其余Provided依赖仍保持默认排除逻辑,避免不必要的包打入可执行jar:
// sbt-assembly 2.x 版本适配 assembly / assemblyMergedJars := { val (providedJars, regularJars) = (assembly / assemblyFullClasspath).value .partition(_.configuration.contains(Provided.name)) val logbackIncluded = providedJars.filter { jar => jar.get(moduleID.key).exists(mod => mod.organization == "ch.qos.logback") } regularJars ++ logbackIncluded }
效果核验
配置完成后可满足所有需求:
- 本地开发:IntelliJ导入项目、sbt执行runMain启动应用、testOnly跑单元测试时,logback正常生效,日志按配置输出
- 构件发布:下游用户引入你的类库时,不会传递拉取logback-classic,用户可自由选择任意SLF4J绑定实现,完全符合官方规范
- 可执行包:sbt assembly生成的fat jar内置logback实现,直接通过
java -jar启动即可正常输出日志,无需额外添加日志依赖
类库、框架这类嵌入式组件不应声明对任何SLF4J绑定/实现提供者(如logback-classic)的依赖,仅需依赖slf4j-api即可。若类库声明了对特定SLF4J绑定的传递依赖,相当于将该绑定强制强加给终端用户,违背了SLF4J的设计初衷。注意,声明绑定的非传递依赖(例如仅用于测试场景)不会对终端用户造成影响。
内容的提问来源于stack exchange,提问作者Keith Alcock
相关产品推荐
相关产品推荐

