org.slf4j.Logger
org.slf4j.LoggerFactory
slf4j的实际调用日志在运行时才会动态绑定,基本原理是查找classpath下面的jar包,如果存在slf4j的实现框架,就采用该实现框架。参考下图:
下面分析一下slf4j如何实现运行时的动态绑定日志实现框架
以下代码是org.slf4j.LoggerFactory中的部分
// We need to use the name of the StaticLoggerBinder class, we can't reference
// the class itseld.
private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
private static void singleImplementationSanityCheck() {
try {
ClassLoader loggerFactoryClassLoader = LoggerFactory.class
.getClassLoader();
Enumeration paths;
if (loggerFactoryClassLoader == null) {
paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
} else {
paths = loggerFactoryClassLoader
.getResources(STATIC_LOGGER_BINDER_PATH);
}
List implementationList = new ArrayList();
while (paths.hasMoreElements()) {
URL path = (URL) paths.nextElement();
implementationList.add(path);
}
if (implementationList.size() > 1) {
Util.report("Class path contains multiple SLF4J bindings.");
for (int i = 0; i < implementationList.size(); i++) {
Util.report("Found binding in [" + implementationList.get(i) + "]");
}
Util.report("See " + MULTIPLE_BINDINGS_URL + " for an explanation.");
}
} catch (IOException ioe) {
Util.report("Error getting resources from path", ioe);
}
}
我们的日志系统lib中有一个日志API:slf4j-api.jar,以及不少于一个日志框架(比如log4j,commons-logging等等)
程序运行过程中到底会使用哪个日志框架(log4j or commons-logging)呢。
这个中间需要一个API -> 实现框架的桥梁: 对接包
上面代码可以看出,通过ClassLoader来查找资源"org/slf4j/impl/StaticLoggerBinder.class",
如果有1个资源,这个就是日志实现库对接包了。如果有多个资源,则警告classpath路径下有多个slf4j的实现框架对接包。
那如果有多个实现框架对接包的情况下,到底会用哪个实现框架呢?这个就靠ClassLoader先加载到哪个了,不能确定。
因此不要在classpath下放入多个slf4j的实现框架对接包,避免出错。
上面说到关键的类StaticLoggerBinder.class,这个是判断采用哪个slf4j实现框架的关键。
StaticLoggerBinder类是slf4j组织来写的,目的是为了对接不同的日志框架。
如上图所示,slf4j-log12-xxx.jar slf4j-jdk14-xxx.jar 之类jar中就包含StaticLoggerBinder类。
实际中至少需要在classpath下提供一个实现框架,以及不多于一个对应的对接包
slf4j还有一个功能是,可以方便的迁移不同的日志框架。
比如一个项目是使用commons-logging框架来写日志的。
我们需要迁移到log4j框架来,如何处理呢。
使用slf4j将会非常方便,我们只需要做三步:
1.删除原有的commons-logging包
2.将log4j的jar加入到classpath
3.引入一个日志转换的jar,在这里是jcl-over-slf4j.jar
下面分析一下以上步骤的实现原理
commons-logging框架中的几个核心类是:
org.apache.commons.logging.Log
org.apache.commons.logging.LoggerFactory
老项目采用了commons-logging框架,必然会耦合这几个类,比如使用了如下代码:
org.apache.commons.logging.Log.error("errror msg");
要想使以上代码正常运行,而又实际是调用log4j来处理。这里就需要用到jcl-over-slf4j.jar了
jcl-over-slf4j.jar实际上是覆写了commons-logging中的几个核心类,内部采用类Adaptor,对接到了slf4j的API上面。
即jcl-over-slf4j中也有 org.apache.commons.logging.Log这个类, 他与原生的类完全不同,仅仅是适配到了slf4j-api上。
因为jcl-over-slf4j.jar是slf4j出品,slf4j把代码写到了不属于他们的package下面,感觉有点山寨,怪怪的。
这里只是举例commons-logging -> log4j, 其他的转换也类似,只是需要下载不同的适配包
整理一下日志框架迁移的流程
老日志框架:类比与上例的common-logging代码
新日志框架:类比与上例的log4j
适配包:类比与上例的jcl-over-slf4j.jar
对接包:类比与上上例的slf4j-log4j12-xxx.jar
老日志框架 ---(适配包)---> SLF4J API ---(对接包)---> 新日志框架
大小: 71.9 KB
分享到:
2012-02-10 13:43
浏览 3712
评论