3 slf4j
3.1 简介
与commons-logging相同,slf4j也是一个通用的日志接口,在程序中与其他日志框架结合使用,并对外提供服务。
Simple Logging Facade for Java简称 slf4j,Java简单日志门面系统。在我们的代码中,不需要显式指定具体日志框架(例如:java.util.logging、logback、log4j),而是使用slf4j的API来记录日志便可,最终日志的格式、记录级别、输出方式等通过具体日志框架的配置来实现,因此可以在应用中灵活切换日志系统。
如果你对上面所说的,仍然不太理解。那么,简单的说slf4j可以理解为JDBC,都是提供接口服务,只不过比JDBC更为直观、简单些。在程序中,JDBC需要单独指定具体的数据库实现(例如:mysql),而slf4j并不需要。
接下来,我们讲解下关于slf4j具体的使用。
3.2 slf4j结构
上面的截图,展示的是slf4j搭配log4j使用。
Logger:slf4j日志接口类,提供了trace < debug < info < warn < error这5个级别对应的方法,主要提供了占位符{}的日志打印方式;
Log4jLoggerAdapter:Logger适配器,主要对org.apache.log4j.Logger对象的封装,占位符{}日志打印的方式在此类中实现;
LoggerFactory:日志工厂类,获取实际的日志工厂类,获取相应的日志实现对象;
lLoggerFactory:底层日志框架中日志工厂的中介,再其实现类中,通过底层日志框架中的日志工厂获取对应的日志对象;
StaticLoggerBinder:静态日志对象绑定,在编译期确定底层日志框架,获取实际的日志工厂,也就是lLoggerFactory的实现类;
3.2 使用
同为Java日志接口框架,相对于commons-logging来说,slf4j的使用有点特殊。
在第一篇的文章中,笔者介绍了commons-logging的使用,对于commons-logging来说,无需在pom.xml文件中单独引入日志实现框架,便可进行日志打印。但是,slf4j并不支持此功能,必须在pom.xml中单独引入底层日志实现。
搭配log4j使用:
首先,需要在pom.xml文件中添加依赖:
//slf4j:
org.slf4j
slf4j-api
1.7.20
//slf4j-log4j:
org.slf4j
slf4j-log4j12
1.7.12
//log4j:
log4j
log4j
1.2.17
声明测试代码:
public class slf4j_log4jDemo {
Logger logger = LoggerFactory.getLogger(slf4j_log4jDemo.class);
@Test
public void test() throws IOException {
logger.error("Error Message!");
logger.warn("Warn Message!");
logger.info("Info Message!{}","你好");
logger.debug("Debug Message!");
logger.trace("Trace Message!");
}
}
接下来,在classpath下定义配置文件:log4j.xml:
对于slf4j来说,它只提供了一个核心模块--slf4j-api,这个模块下只有日志接口,没有具体的实现,所以在实际开发总需要单独添加底层日志实现。但是,这些底层日志类实际上跟slf4j并没有任何关系,因此slf4j又通过增加一层日志中间层来转换相应的实现,例如上文中的slf4j-log4j12。
上图,是官方文档中slf4j与其他日志框架相结合的使用情况,具体总结如下:
logback:logback-classic 、logback-core
java.util.logging.Logging:slf4j-jdk14
commons-logging:jcl-over-slf4j
其中,commons-logging比较特殊。由于commons-logging诞生的比较早,一些年限久远的系统大体上都使用了commons-logging和log4j的日志框架组合,大名鼎鼎的spring框架也依然在使用commons-logging框架。那么,此时你的新系统如果想使用slf4j该如何处理?
这会,就需要引入jcl-over-slf4j.jar包了,它会将commons-logging的“骗入”到slf4j中来,实现日志框架结合;
3.3 源码分析
以下源码基于slf4j-1.7.20、slf4j-log4j12-1.7.12和log4j-1.2.17(使用slf4j和log4j结合):
org.slf4j.LoggerFactory类:
public final class LoggerFactory {
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;
private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
//初始化状态,默认为0;
static int INITIALIZATION_STATE = UNINITIALIZED;
//获取日志对象:
public static Logger getLogger(Class> claz