首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Coding
V2EX  ›  Java

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

  •  
  •   stephCurry · 52 天前 · 1679 次点击
    这是一个创建于 52 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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] 呢?

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

    如果想丑陋的且非常简单的改变,在你的 src/main/java 下面建一个 org.slf4j.LoggerFactory,把原有的代码拷过来,然后修改相关的逻辑,程序运行的时候就会加载到动了手脚的这个
        6
    stephCurry   51 天前
    @airfling 我也想去, 但是去不掉啊
        7
    airfling   51 天前
    exclude group: 'org.slf4j', module: 'slf4j-log4j12'
    exclude group: 'log4j', module: 'log4j'
    这两个你加上试试
        8
    git00ll   51 天前
    #### 将你想使用的实现类配置在第一个,下面 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   51 天前
    看了下 github 上你说的这个项目,POM 里直接引用的是 slf4j-simple,但是代码里只使用了 slf4j-api 的 LoggerFactory 和 Logger,所以直接排除 slf4j-simple 就行了
        10
    stephCurry   51 天前
    @Jrue0011 不行,exclude 不掉,soot-infoflow-cmd-jar-with-dependencies.jar code 里已经硬引用了 org/slf4j
        11
    Jrue0011   51 天前   ♥ 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   44 天前
    既然是`硬包含`了 SimpleLoggerFactory,exclude 不掉,我列举下能想到的几种做法:
    1. 使用 soot-infoflow-cmd.jar 不要用 with-dependencies.jar
    2. 可调整 maven 仓库吗?下载 with-dependencies.jar ,删了不想要的类,发布上去
    3. `considered random` 视为随机,并没有说它是真的随机,根据 java 的加载,好像是看引入顺序的,一般没调整的话就是按照 jar 文件名顺序载入类。根据这就可以用“从文件加载类”+反射机器 自行调整具体的 log factory
        13
    lxk11153   44 天前
    3. `considered random` 视为随机,并没有说它是真的随机,根据 java 的加载,是看引入顺序的,一般没调整的话就是按照 jar 文件名顺序载入类。根据这就可以用“从文件加载类”(可能加上反射机制) 自行调整到你要的 log factory
        15
    stephCurry   39 天前
    @lxk11153 把 jar 文件名改成 a 开头/ z 开头,还是不行。。。。 自己写的` StaticLoggerBinder implements LoggerFactoryBinder ` 不知怎么也没扫到, 只能尝试去 rebuild FlowDroid 了
        16
    lxk11153   39 天前   ♥ 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   39 天前
    @lxk11153 谢谢! 方便的话 可否 atob d2VjaGF0OiAxMzA1MTE1MjY1MA==
        18
    lxk11153   39 天前
    @lxk11153 #16 至于 Windows 好像 任务管理器 右键列标题把 command 显示出来就能看到,至于能否复制出来不清楚,自己查找解决办法
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   972 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 29ms · UTC 21:20 · PVG 05:20 · LAX 13:20 · JFK 16:20
    ♥ Do have faith in what you're doing.