前言
Slf4j
SLF4J,全称 Simple Logging Facade for Java,是一个用于Java编程语言的日志系统抽象层。它为多种现有日志框架(例如Log4j、java.util.logging等)提供了统一的接口, 但自身并不实现日志功能。
SLF4J 允许用户在部署时选择适当的日志库(即日志框架),比如 Logback、Log4j 等。
Logback
Logback 是一个实现日志功能的库,它由Log4j的创建者设计。Logback被设计成Log4j的一个卓越替代品,它具有更好的性能、自动重加载配置文件、更丰富的日志格式以及内置日志归档等特点。
简单来说,SLF4J为Java提供了一个统一的日志接口,而Logback是一个具体的日志库,可以与SLF4J API结合起来使用。
注意,其它日志实现如log4j等结合slf4j的时候是需要桥接包,而logback是直接实现了slf4j。
Slf4j初始化源码分析
slf4j在代码中初始化一个Logger对象时,如下,调用LoggerFactory.getLogger()方法:
private final Logger logger = LoggerFactory.getLogger(this.getClass());
查看getLogger方法:
public static Logger getLogger(String name) {
// logback实现了slf4j的ILoggerFactory接口,关键也在于这个地方
ILoggerFactory iLoggerFactory = getILoggerFactory();
return iLoggerFactory.getLogger(name);
}
logback针对ILoggerFactory的实现类是:ch.qos.logback.classic.LoggerContext。
所以可以直接查看LoggerContext.getLogger()方法。
可以看到最终是调用到这个方法:
这个地方不是配方重点,这里分析下初始化的时候如何构造LoggerContext实例:
ILoggerFactory iLoggerFactory = getILoggerFactory();
通过追踪方法调用,可以看到最终调用的是这个bind()方法(具体调用的源码细节,可以自己点进去看一下,代码不多,不啰嗦了):
private final static void bind() {
try {
Set<URL> staticLoggerBinderPathSet = null;
// 不检查安卓系统的
if (!isAndroid()) {
// 这里是找到所有org/slf4j/impl/StaticLoggerBinder.class的jar路径
staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
// 如果项目有多个日志框架的实现,平常启动项目不是会打印一些日志:Class path contains multiple SLF4J bindings.等
// 就是这这个地方打印的,日志实现冲突
reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
}
// 每个实现slf4j的日志或者桥接包都会有这个org/slf4j/impl/StaticLoggerBinder.class类
StaticLoggerBinder.getSingleton();
INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
reportActualBinding(staticLoggerBinderPathSet);
} catch (NoClassDefFoundError ncde) {
// 下面代码忽略了
} catch (java.lang.NoSuchMethodError nsme) {
} catch (Exception e) {
failedBinding(e);
throw new IllegalStateException("Unexpected initialization failure", e);
} finally {
postBindCleanUp();
}
}
StaticLoggerBinder.getSingleton();这个注释里说了,每个实现或者桥接包都有这个类的,比如logback:
这个地方也是slf4j初始化的精髓,没有这个类就抛异常了。
而关于StaticLoggerBinder的初始化,也很平常:
就是通过静态代码块来初始化logback了。