SLF4J(Simple logging Facade for Java)是一个日志框架的适配器。
如果一个项目已经使用了log4j,而你加载了Apache Active MQ——它依赖于于另外一个日志类库logback,那么你就需要把logback也加载进来。但如果Apache Active MQ使用了SLF4J,你可以继续使用log4j,而无需加载和维护一个新的日志框架。或者添加XXX-over-slf4j.jar可以将xxx的日志输出转向到slf4j,然后slf4j将日志交由真正的日志实现框架来输出
几个jar提一下:
jcl-over-slf4j 将Commons Logging API输出转向到slf4j输出。
log4j-1.2-api 将log4j适配到log4j2,从而程序不用修改。
log4j-jcl 将Commons Logging API输出转向到log4j2输出。
Slf4j启动
关键在于slf4j-api-xxx.jar中org.slf4j.LoggerFactory:
// org/slf4j/impl/StaticLoggerBinder.class为log4j-slf4j-impl-xxxjar中的类,所以用字符串声明,避免具体依赖。
private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
private static Set findPossibleStaticLoggerBinderPathSet() {
// use Set instead of list in order to deal with bug #138
// LinkedHashSet appropriate here because it preserves insertion order during iteration
Set staticLoggerBinderPathSet = new LinkedHashSet();
try {
//一般就是AppClassLoader
ClassLoader loggerFactoryClassLoader = LoggerFactory.class
.getClassLoader();
Enumeration paths;
//每一种类加载器加载指定的*.class文件会得到不同的Class,这里必须要保证LoggerFactory的类加载器与StaticLoggerBinder的类加载是相同的。
//ClassLoader.getSystemResources方法会调getSystemClassLoader()即启动当前application的classloader,一般就是AppClassLoader,若返回为空,则调getBootstrapResources()。
//若存在多个日志框架,则类加载的URL有多个,所以是Enumeration
if (loggerFactoryClassLoader == null) {//LoggerFactory为Bootstrap Loader载入。
paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
} else {
paths = loggerFactoryClassLoader
.getResources(STATIC_LOGGER_BINDER_PATH);
}
while (paths.hasMoreElements()) {
URL path = (URL) paths.nextElement();
staticLoggerBinderPathSet.add(path);
}
} catch (IOException ioe) {
......
}
return staticLoggerBinderPathSet;
}
LoggerFactory的bind()方法会调用findPossibleStaticLoggerBinderPathSet(),若返回Set的大小超过1,则警告。通过StaticLoggerBinder.getSingleton()完成初始化,即实例化具体的factory赋值给内部的ILoggerFactory,如 loggerFactory = new Log4jLoggerFactory();。
不同的日志框架有相应的不同的xxx-slf4j-impl.jar,不同的StaticLoggerBinder.class决定了slf4j使用哪种日志框架。