log4j-over-slf4的log4j Loger加载问题

log4j-over-slf4是通过定义和log4j同包名的org.apache.log4j.Logger来实现替换log4j的,但log4j-over-slf4怎么能确定JVM一定会加载它定义的这个Logger?

 

 

 

做了一个测试,发现在classpath中,log4j和slf4j两个包谁在前面先加载:

/home/yunpeng/.m2/repository/log4j/log4j/1.2.14/log4j-1.2.14.jar:

/home/yunpeng/.m2/repository/org/slf4j/log4j-over-slf4j/1.7.4/log4j-over-slf4j-1.7.4.jar

 

测试代码

package com.taobao.hasf.tlog.proxy.gather;

import org.apache.log4j.Logger;

public class LogGathersTester {

	public static void main(String[] args) throws InterruptedException {
		System.out.println(Boo.test);
		System.out.println(Logger.getLogger("root"));
		Thread.currentThread().join();


}

 

 测试脚本:

slf4j在前
/duitang/dist/sys/java/bin/java -Dfile.encoding=UTF-8 -classpath /duitang/dist/app/branches/tlog/tlog-proxy/target/test-classes:/duitang/dist/app/branches/tlog/tlog-proxy/target/classes:/home/yunpeng/.m2/repository/org/slf4j/slf4j-api/1.7.4/slf4j-api-1.7.4.jar:/home/yunpeng/.m2/repository/org/slf4j/log4j-over-slf4j/1.7.4/log4j-over-slf4j-1.7.4.jar:/home/yunpeng/.m2/repository/log4j/log4j/1.2.14/log4j-1.2.14.jar com.taobao.hasf.tlog.proxy.gather.LogGathersTester
hello
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
org.apache.log4j.Logger@37dd7056
log4j在前
/duitang/dist/sys/java/bin/java -Dfile.encoding=UTF-8 -classpath /duitang/dist/app/branches/tlog/tlog-proxy/target/test-classes:/duitang/dist/app/branches/tlog/tlog-proxy/target/classes:/home/yunpeng/.m2/repository/log4j/log4j/1.2.14/log4j-1.2.14.jar:/home/yunpeng/.m2/repository/org/slf4j/slf4j-api/1.7.4/slf4j-api-1.7.4.jar:/home/yunpeng/.m2/repository/org/slf4j/log4j-over-slf4j/1.7.4/log4j-over-slf4j-1.7.4.jar: com.taobao.hasf.tlog.proxy.gather.LogGathersTester
hello
org.apache.log4j.Logger@12276af2

 

那么在tomcat容器中如何能保证一定先加载log4j-over-slf4j包中定义的Logger呢?

 

 

解决办法:

应用只依赖log4j-over-slf4j,不过有点风险,参考:http://stackoverflow.com/questions/4028703/issues-replacing-log4j-with-logback-log4j-over-slf4j-jar-shortcomings

java 界里有许多实现日志功能的工具,最早得到广泛使用的是 log4j,许多应用程序的日志部分都交给了 log4j,不过作为组件开发者,他们希望自己的组件不要紧紧依赖某一个工具,毕竟在同一个时候还有很多其他很多日志工具,假如一个应用程序用到了两个组件,恰好两个组件使用不同的日志工具,那么应用程序就会有两份日志输出了。 为了解决这个问题,Apache Commons Logging (之前叫 Jakarta Commons Logging,JCL)粉墨登场,JCL 只提供 log 接口,具体的实现则在运行时动态寻找。这样一来组件开发者只需要针对 JCL 接口开发,而调用组件的应用程序则可以在运行时搭配自己喜好的日志实践工具。 所以即使到现在你仍会看到很多程序应用 JCL + log4j 这种搭配,不过当程序规模越来越庞大时,JCL的动态绑定并不是总能成功,具体原因大家可以 Google 一下,这里就不再赘述了。解决方法之一就是在程序部署时静态绑定指定的日志工具,这就是 SLF4J 产生的原因。 跟 JCL 一样,SLF4J 也是只提供 log 接口,具体的实现是在打包应用程序时所放入的绑定器(名字为 slf4j-XXX-version.jar)来决定,XXX 可以是 log4j12, jdk14, jcl, nop 等,他们实现了跟具体日志工具(比如 log4j)的绑定及代理工作。举个例子:如果一个程序希望用 log4j 日志工具,那么程序只需针对 slf4j-api 接口编程,然后在打包时再放入 slf4j-log4j12-version.jar 和 log4j.jar 就可以了。 现在还有一个问题,假如你正在开发应用程序所调用的组件当中已经使用了 JCL 的,还有一些组建可能直接调用了 java.util.logging,这时你需要一个桥接器(名字为 XXX-over-slf4j.jar)把他们的日志输出重定向到 SLF4J,所谓的桥接器就是一个假的日志实现工具,比如当你把 jcl-over-slf4j.jar 放到 CLASS_PATH 时,即使某个组件原本是通过 JCL 输出日志的,现在却会被 jcl-over-slf4j “骗到”SLF4J 里,然后 SLF4J 又会根据绑定器把日志交给具体的日志实现工具。过程如下 Component | | log to Apache Commons Logging V jcl-over-slf4j.jar — (redirect) —> SLF4j —> slf4j-log4j12-version.jar —> log4j.jar —> 输出日志 看到上面的流程图可能会发现一个有趣的问题,假如在 CLASS_PATH 里同时放置 log4j-over-slf4j.jar 和 slf4j-log4j12-version.jar 会发生什么情况呢?没错,日志会被踢来踢去,最终进入死循环。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值