SLF4J 冲突, 如何指定其中一个为实现类

2019-10-21 22:18:09 +08:00
 stephCurry
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Actual binding is of type [org.slf4j.impl.SimpleLoggerFactory]

Exception in thread "main" java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. Either remove Logback or the competing implementation

from SLF4J multiple_bindings Doc

NOTE The warning emitted by SLF4J is just that, a warning. Even when multiple bindings are present, SLF4J will pick one logging framework/implementation and bind with it. The way SLF4J picks a binding is determined by the JVM and for all practical purposes should be considered random.

如上所示, 由于 SLF4J binding 是 random 的,所以这里就随机引用到了 Actual binding is of type [org.slf4j.impl.SimpleLoggerFactory] 导致 IllegalArgumentException

把此 gradle 项目换成 maven 时,它就随机绑定到了 Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder] , 此时启动没问题, 但是对于 gradle 项目还是想去解决这个问题。

主要问题还是引的 jar 依赖( soot-infoflow-cmd )里直接把 slf4j 侵入到代码里了,所以无法在这个依赖下 exclude 掉内部的 slf4j。

解决方式也说了, Either remove Logback or the competing implementation , 要删 logback,可是我不想 exclude springboot-starter-logging, 要么 competing implementation, 那么这里如何去 compete implementation 呢?如何让它强制 bind [ch.qos.logback.classic.util.ContextSelectorStaticBinder] 呢?

5978 次点击
所在节点    Java
18 条回复
Samuelcc
2019-10-22 00:32:38 +08:00
slf4j 和 它的实现的依赖应该是分开的吧,代码里如果直接用的 slf4j 的接口,应该 exclude 掉对应实现就行,不用 exclude slf4j。
NeinChn
2019-10-22 01:00:14 +08:00
一般 exclude 可能因为 level 太深依赖关系太复杂 exclude 比较麻烦
通用做法是加个空白的实现 deploy 到 maven 仓库,然后在 top level 显式声明这个依赖
比如 slf4j-simple,自己写个
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>empty-version</version>
airfling
2019-10-22 08:37:11 +08:00
我把 slf4j 的全去掉,只用 logback,用着没啥问题
dif
2019-10-22 09:29:58 +08:00
@airfling 这种情况仅适合自己用。最好还是用 slf4j 吧,切换日志实现都方便。
qwerthhusn
2019-10-22 09:33:53 +08:00
org.slf4j.LoggerFactory#bind
这个方法,看了一圈没有能找到控制其实现流程的地方。

如果想丑陋的且非常简单的改变,在你的 src/main/java 下面建一个 org.slf4j.LoggerFactory,把原有的代码拷过来,然后修改相关的逻辑,程序运行的时候就会加载到动了手脚的这个
stephCurry
2019-10-22 10:02:31 +08:00
@airfling 我也想去, 但是去不掉啊
airfling
2019-10-22 10:15:24 +08:00
exclude group: 'org.slf4j', module: 'slf4j-log4j12'
exclude group: 'log4j', module: 'log4j'
这两个你加上试试
git00ll
2019-10-22 11:40:51 +08:00
#### 将你想使用的实现类配置在第一个,下面 slf4j-simple 配置都在 logback-classic 前面,使用的就是 slf4j-simple

```

dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.28'
compile group: 'org.slf4j', name: 'slf4j-simple', version: '1.7.28'
compile group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.3'
}



public static void main(String[] args) throws IOException {
Logger log = LoggerFactory.getLogger(Test.class);
log.info("info");
}

```
Jrue0011
2019-10-22 13:42:14 +08:00
看了下 github 上你说的这个项目,POM 里直接引用的是 slf4j-simple,但是代码里只使用了 slf4j-api 的 LoggerFactory 和 Logger,所以直接排除 slf4j-simple 就行了
stephCurry
2019-10-22 15:57:05 +08:00
@Jrue0011 不行,exclude 不掉,soot-infoflow-cmd-jar-with-dependencies.jar code 里已经硬引用了 org/slf4j
Jrue0011
2019-10-22 17:18:46 +08:00
@stephCurry 是不是直接下载的 soot-infoflow-cmd-jar-with-dependencies.jar 这个 jar 包然后引用到项目里?是的话可以直接打开压缩包删掉 org/slf4j/impl 目录。

但既然用 gradle 和 maven 管理依赖了,好点的做法是下载他的项目源码,maven 打包安装到本地仓库,然后就可以在自己项目的 pom.xml 或 build.gradle 里引用了,但是打包的时候由于环境问题可能出错。。。

https://github.com/secure-software-engineering/FlowDroid
参考 README.md 的 Building The Tool With Maven
lxk11153
2019-10-29 14:11:07 +08:00
既然是`硬包含`了 SimpleLoggerFactory,exclude 不掉,我列举下能想到的几种做法:
1. 使用 soot-infoflow-cmd.jar 不要用 with-dependencies.jar
2. 可调整 maven 仓库吗?下载 with-dependencies.jar ,删了不想要的类,发布上去
3. `considered random` 视为随机,并没有说它是真的随机,根据 java 的加载,好像是看引入顺序的,一般没调整的话就是按照 jar 文件名顺序载入类。根据这就可以用“从文件加载类”+反射机器 自行调整具体的 log factory
lxk11153
2019-10-29 14:13:33 +08:00
3. `considered random` 视为随机,并没有说它是真的随机,根据 java 的加载,是看引入顺序的,一般没调整的话就是按照 jar 文件名顺序载入类。根据这就可以用“从文件加载类”(可能加上反射机制) 自行调整到你要的 log factory
PoetAndPoem
2019-10-29 14:39:11 +08:00
stephCurry
2019-11-03 10:57:06 +08:00
@lxk11153 把 jar 文件名改成 a 开头/ z 开头,还是不行。。。。 自己写的` StaticLoggerBinder implements LoggerFactoryBinder ` 不知怎么也没扫到, 只能尝试去 rebuild FlowDroid 了
lxk11153
2019-11-03 14:23:17 +08:00
@stephCurry #15
private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";

你可以把你 java 的 command 发出来,我来看看
linux: pgrep -af "java" macos: pgrep -lf "java" 至于 Windows 可以用 docs.microsoft.com/zh-cn/sysinternals/downloads/process-explorer 右键列标题把 command 显示出来就能看到
stephCurry
2019-11-03 15:30:49 +08:00
@lxk11153 谢谢! 方便的话 可否 atob d2VjaGF0OiAxMzA1MTE1MjY1MA==
lxk11153
2019-11-03 17:53:31 +08:00
@lxk11153 #16 至于 Windows 好像 任务管理器 右键列标题把 command 显示出来就能看到,至于能否复制出来不清楚,自己查找解决办法

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/611554

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX