要使用SLF4J,得包含对"org.slf4j:slf4j-api"的依赖。
二、两个简单的例子
2.1、具体日志框架是默认实现
org.slf4j
slf4j-api
1.7.12
2)Java代码片段
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(Main.class);
logger.error("Hello World");
System.out.println(logger.getClass());
}
}
3)运行结果
如图1
图1
org.slf4j
slf4j-api
1.7.12
org.slf4j
slf4j-simple
1.7.12
2)Java代码片段
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(Main.class);
logger.error("Hello World");
System.out.println(logger.getClass());
}
}
3)运行结果
如图2
图2
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(Main.class);
logger.error("Hello World");
System.out.println(logger.getClass());
}
}
在不使用适配器类方案中,logger指向的类实例A独立实现日志操作功能;在使用适配器类方案中,logger指向的类实例A中包含有另外的日志框架中的日志记录类实例B,A的日志操作功能的实现是通过委托给B来实现的。
org.slf4j
slf4j-api
1.7.12
ch.qos.logback
logback-classic
1.0.13
以上代码中的logger指向的类实例A为"ch.qos.logback.classic.Logger"的实例对象,A独立实现日志操作功能
"SLF4J+Simple"方案和"SLF4J+NOP"方案都是以上这种类型。
org.slf4j
slf4j-api
1.7.12
org.slf4j
slf4j-log4j12
1.7.12
log4j
log4j
1.2.17
以上代码中的logger指向的类实例A为"org.slf4j.impl.Log4jLoggerAdapter"的实例对象,A中包含一个"org.apache.log4j.Logger"类实例B,A的日志操作委托给B来实现
org.slf4j
slf4j-api
1.7.12
org.slf4j
slf4j-jcl
1.7.12
commons-logging
commons-logging
1.1
log4j
log4j
1.2.17
而根据 《Java日志框架——JCL》在"SLF4J+SLF4J-JCL+JCL+Log4J"方案中,以上代码中的logger指向的类实例A为"org.slf4j.impl.JCLLoggerAdapter"的实例对象,A中包含一个"org.apache.commons.logging.impl.Log4JLogger"类实例B,实例B中包含一个"org.apache.log4j.Logger“类实例C,A的日志操作委托给B来实现,B又委托给C来实现
”SLF4J+SLF4J-Jdk14+Java Logging API“方案也是以上这种类型
3.3、绑定关系图示
如图3
图3
org.slf4j
slf4j-api
1.7.12
org.slf4j
slf4j-log4j12
1.7.12
log4j
log4j
1.2.17
通过查看"org.slf4j:slf4j-log4j12:1.7.12"的pom.xml,可以发现其中有如下片段
org.slf4j
slf4j-api
log4j
log4j
也就是说"org.slf4j:slf4j-log4j12:1.7.12"中含有对"org.slf4j:slf4j-api"和"log4j:log4j"的依赖,其实想想也是,在"org.slf4j:slf4j-log4j12:1.7.12"中的"org.slf4j.impl.Log4jLoggerAdapter"类既要继承实现"org.slf4j:slf4j-api"中的"org.slf4j.Logger"类,也要包含"log4j:log4j"中的"org.apache.log4j.Logger"类实例作为完成实际日志操作功能的对象,因而"org.slf4j:slf4j-log4j12:1.7.12"自然得包含对这两个包的依赖
org.slf4j
slf4j-log4j12
1.7.12
但是为了更好的可读性和更高的掌控度,还是使用刚开始的完整的声明方案比较好。
五、SLF4J绑定具体的日志框架的原理
根据"2.2、具体日志框架是slf4j-simple"中的简单例子来进行说明。
执行"Logger logger = LoggerFactory.getLogger(Main.class);"语句的时候发生了什么?
1)查看"org.slf4j.LoggerFactory"的源代码可以发现,其中有如下这些方法
public static Logger getLogger(Class> clazz) {
Logger logger = getLogger(clazz.getName());
if(DETECT_LOGGER_NAME_MISMATCH) {
Class autoComputedCallingClass = Util.getCallingClass();
if(nonMatchingClasses(clazz, autoComputedCallingClass)) {
Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", new Object[]{logger.getName(), autoComputedCallingClass.getName()}));
Util.report("See http://www.slf4j.org/codes.html#loggerNameMismatch for an explanation");
}
}
return logger;
}
public static Logger getLogger(String name) {
ILoggerFactory iLoggerFactory = getILoggerFactory();
return iLoggerFactory.getLogger(name);
}
public static ILoggerFactory getILoggerFactory() {
if(INITIALIZATION_STATE == 0) {
INITIALIZATION_STATE = 1;
performInitialization();
}
switch(INITIALIZATION_STATE) {
case 1:
return TEMP_FACTORY;
case 2:
throw new IllegalStateException("org.slf4j.LoggerFactory could not be successfully initialized. See also http://www.slf4j.org/codes.html#unsuccessfulInit");
case 3:
return StaticLoggerBinder.getSingleton().getLoggerFactory();
case 4:
return NOP_FALLBACK_FACTORY;
default:
throw new IllegalStateException("Unreachable code");
}
}
private static final void performInitialization() {
bind();
if(INITIALIZATION_STATE == 3) {
versionSanityCheck();
}
}
private static final void bind() {
String msg;
try {
Set e = findPossibleStaticLoggerBinderPathSet();
reportMultipleBindingAmbiguity(e);
StaticLoggerBinder.getSingleton();
INITIALIZATION_STATE = 3;
reportActualBinding(e);
fixSubstitutedLoggers();
} catch (NoClassDefFoundError var2) {
msg = var2.getMessage();
if(!messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {
failedBinding(var2);
throw var2;
}
INITIALIZATION_STATE = 4;
Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\".");
Util.report("Defaulting to no-operation (NOP) logger implementation");
Util.report("See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.");
} catch (NoSuchMethodError var3) {
msg = var3.getMessage();
if(msg != null && msg.indexOf("org.slf4j.impl.StaticLoggerBinder.getSingleton()") != -1) {
INITIALIZATION_STATE = 2;
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 var3;
} catch (Exception var4) {
failedBinding(var4);
throw new IllegalStateException("Unexpected initialization failure", var4);
}
}
依次调用执行的顺序为
Logger getLogger(Class> clazz)()4、在图03中的"native implementaion"和"non-native implementation"不是以”“是否以非Java语言实现”为区分标准,而是以“是否直接继承'org.slf4j.Logger'类”为区分标准
5、现在流行的日志框架解决方案是:SLF4J+Logback