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] 呢?
1
Samuelcc 2019-10-22 00:32:38 +08:00 via Android
slf4j 和 它的实现的依赖应该是分开的吧,代码里如果直接用的 slf4j 的接口,应该 exclude 掉对应实现就行,不用 exclude slf4j。
|
2
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> |
3
airfling 2019-10-22 08:37:11 +08:00
我把 slf4j 的全去掉,只用 logback,用着没啥问题
|
5
qwerthhusn 2019-10-22 09:33:53 +08:00
org.slf4j.LoggerFactory#bind
这个方法,看了一圈没有能找到控制其实现流程的地方。 如果想丑陋的且非常简单的改变,在你的 src/main/java 下面建一个 org.slf4j.LoggerFactory,把原有的代码拷过来,然后修改相关的逻辑,程序运行的时候就会加载到动了手脚的这个 |
6
stephCurry OP @airfling 我也想去, 但是去不掉啊
|
7
airfling 2019-10-22 10:15:24 +08:00
exclude group: 'org.slf4j', module: 'slf4j-log4j12'
exclude group: 'log4j', module: 'log4j' 这两个你加上试试 |
8
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"); } ``` |
9
Jrue0011 2019-10-22 13:42:14 +08:00
看了下 github 上你说的这个项目,POM 里直接引用的是 slf4j-simple,但是代码里只使用了 slf4j-api 的 LoggerFactory 和 Logger,所以直接排除 slf4j-simple 就行了
|
10
stephCurry OP @Jrue0011 不行,exclude 不掉,soot-infoflow-cmd-jar-with-dependencies.jar code 里已经硬引用了 org/slf4j
|
11
Jrue0011 2019-10-22 17:18:46 +08:00 1
@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 |
12
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 |
13
lxk11153 2019-10-29 14:13:33 +08:00
3. `considered random` 视为随机,并没有说它是真的随机,根据 java 的加载,是看引入顺序的,一般没调整的话就是按照 jar 文件名顺序载入类。根据这就可以用“从文件加载类”(可能加上反射机制) 自行调整到你要的 log factory
|
14
PoetAndPoem 2019-10-29 14:39:11 +08:00
|
15
stephCurry OP @lxk11153 把 jar 文件名改成 a 开头/ z 开头,还是不行。。。。 自己写的` StaticLoggerBinder implements LoggerFactoryBinder ` 不知怎么也没扫到, 只能尝试去 rebuild FlowDroid 了
|
16
lxk11153 2019-11-03 14:23:17 +08:00 1
@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 显示出来就能看到 |
17
stephCurry OP @lxk11153 谢谢! 方便的话 可否 atob d2VjaGF0OiAxMzA1MTE1MjY1MA==
|
18
lxk11153 2019-11-03 17:53:31 +08:00
@lxk11153 #16 至于 Windows 好像 任务管理器 右键列标题把 command 显示出来就能看到,至于能否复制出来不清楚,自己查找解决办法
|