日志框架:slf4j
日志实现:log4j2
桥接包:log4j-slf4j-impl
桥接包log4j-slf4j-impl起到适配的作用,因为市面上的日志实现互不兼容,日志框架slf4j要想适用于日志实现log4j2,就需要使用桥接包
slf4j使用LoggerFactory创建Logger进行日志打印,底层实际上调用了log4j-slf4j-impl的StaticLoggerBinder类创建一个Log4jLoggerFactory,然后再由这个Log4jLoggerFactory创建一个Log4j2的Logger对象,这个Logger封装在log4j-slf4j-impl中的Log4jLogger里面,最后将Log4jLogger返回给slf4j,每次slf4j进行日志打印,实际上是log4j-slf4j-impl中的Log4jLogger调用log4j2进行日志打印
如果没有 log4j-slf4j-impl桥接包,slf4j将创建一个对象,里面都是空方法,所以不会打印出日志
具体流程
<!-- 日志实现 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.1</version>
</dependency>
<!-- 日志桥接包 桥接包的版本须对应log4j2的版本 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.1</version>
</dependency>
<!-- 日志框架(门面) -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
</dependency>
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Test {
//slf4j获取logger进行日志打印
private static final Logger logger= LoggerFactory.getLogger(Test.class);
public static void main(String[] args) {
logger.info("slf4j 打印日志");
}
}
//LoggerFactory(slf4j)
public static Logger getLogger(String name) {
/*
ILoggerFactory 是一个接口,实际上getILoggerFactory返回的是Log4jLoggerFactory(桥接包提供,ILoggerFactory 的实现类)
*/
ILoggerFactory iLoggerFactory = getILoggerFactory();
/*
Log4jLoggerFactory(桥接包)创建Logger ,实际上调用了它的父抽象类AbstractLoggerAdapter中的getLogger方法
getLogger()
1、创建LoggerContext(Log4j2)
2、调用Log4jLoggerFactory(子类)的newLogger方法,根据LoggerContext生成ExtendedLogger(log4j2用来打印日志的)
3、使用Log4jLogger封装(转换)ExtendedLogger,返回Log4jLogger的一个实例(也就是slf4j的LoggerFactory生成的Logger)
备注:AbstractLoggerAdapter里有一个Map,用来存储每个类创建的<LoggerContext(用来生成log4j2的logger),<LogName(日志标识), logger(桥接包中的,slf4j调用该实现)>>
protected final Map<LoggerContext, ConcurrentMap<String, L>> registry = new WeakHashMap<LoggerContext, ConcurrentMap<String, L>>();
在执行第二步时,都会查看map中是否存在LoggerContext,如果存在,获取返回,不存在则执行第二三步
*/
return iLoggerFactory.getLogger(name);
}
1、创建ILoggerFactory 的实现类
//LoggerFactory(slf4j)
public static ILoggerFactory getILoggerFactory() {
/*
static final int UNINITIALIZED = 0;
static final int ONGOING_INITIALIZATION = 1;
static final int FAILED_INITIALIZATION = 2;
static final int SUCCESSFUL_INITIALIZATION = 3;
static final int NOP_FALLBACK_INITIALIZATION = 4;
static int INITIALIZATION_STATE = UNINITIALIZED;
*/
if (INITIALIZATION_STATE == UNINITIALIZED) {
//设置为正在初始化状态
INITIALIZATION_STATE = ONGOING_INITIALIZATION;
//验证StaticLoggerBinder类(桥接包)是不是log4j2需要的桥接包,正常则设置状态为成功
performInitialization();
}
//判断加载状态
switch (INITIALIZATION_STATE) {
case SUCCESSFUL_INITIALIZATION:
//成功则返回Log4jLoggerFactory
return StaticLoggerBinder.getSingleton().getLoggerFactory();
case NOP_FALLBACK_INITIALIZATION: //org/slf4j/impl/StaticLoggerBinder类没有发现异常
//没有找到适合的StaticLoggerBinder,则出现异常,这个状态返回一个没有实现的NOPLoggerFactory,在getLogger()时返回一个没有实现的Logger,该logger可以正常的调用info这些日志打印方法,但是这些方法都是没有任何实现的
//目的是程序在缺少对应桥接包的时候,还能够保证业务的正常执行,只是不会打印日志而已
return NOP_FALLBACK_FACTORY;
case FAILED_INITIALIZATION: //其他异常
//直接抛异常,没有捕获则程序中断
throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
case ONGOING_INITIALIZATION:
return TEMP_FACTORY;
}
throw new IllegalStateException("Unreachable code");
}
//LoggerFactory
private final static void performInitialization() {
bind();
if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) {
versionSanityCheck();
}
}
//
private final static void bind() {
try {
Set<URL> staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
// the next line does the binding
StaticLoggerBinder.getSingleton();
INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
reportActualBinding(staticLoggerBinderPathSet);
fixSubstitutedLoggers();
} catch (NoClassDefFoundError ncde) {
String msg = ncde.getMessage();
if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {
INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\".");
Util.report("Defaulting to no-operation (NOP) logger implementation");
Util.report("See " + NO_STATICLOGGERBINDER_URL
+ " for further details.");
} else {
failedBinding(ncde);
throw ncde;
}
} catch (java.lang.NoSuchMethodError nsme) {
String msg = nsme.getMessage();
if (msg != null && msg.indexOf("org.slf4j.impl.StaticLoggerBinder.getSingleton()") != -1) {
INITIALIZATION_STATE = FAILED_INITIALIZATION;
Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding.");
Util.report("Your binding is version 1.5.5 or earlier.");
Util.report("Upgrade your binding to version 1.6.x.");
}
throw nsme;
} catch (Exception e) {
failedBinding(e);
throw new IllegalStateException("Unexpected initialization failure", e);
}
}