简介
简单日志门面(Simple Logging Facade For Java)
SLF4J主要是为了给Java日志访问提供一套标准、规范的API框架,
其主要意义在于提供接口,具体的实现可以交由其他日志框架,如log4j、logback、log4j2。
对于一般的Java项目而言,日志框架会选择slf4j-api作为门面,配上具体的实现框架,中间使用桥接器完成桥接。
所以我们可以得出SLF4J最重要的两个功能就是对于日志框架的绑定以及日志框架的桥接。
slf4j+log4j
依赖
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.21</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.21</version></dependency>
使用入口
Logger logger = LoggerFactory.getLogger(Slf4jAndLog4j.class);logger.info("this is slf4j&log4j test:{}",123);
log4j的配置文件参见:log4j日志框架的使用-CSDN博客
slf4j+logback
依赖
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.1.7</version>
</dependency>
使用入口
Logger logger = LoggerFactory.getLogger(Slf4jAndLogback.class);
logger.info("this is slf4j&logback test:{}",123);
logback配置参见:logback日志框架使用-CSDN博客
slf4j+log4j2
依赖
<!--sl4j日志门面--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.25</version></dependency><!--log4j适配器--><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><version>2.12.1</version></dependency><!--log4j2实现--><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.12.1</version></dependency>
使用入口
Logger logger = LoggerFactory.getLogger(Slf4jAndLog4j2.class);
logger.info("this is slf4j&log4j2 test:{}",123);
log4j2的配置参见:log4j2日志框架使用-CSDN博客
实现原理
代码解析入口:
LoggerFactory.getLogger(Slf4jAndLog4j2.class);
该段代码会寻找依赖中的日志实现
如何寻找日志依赖?
org.slf4j.LoggerFactory#findPossibleStaticLoggerBinderPathSet方法会读取依赖中所有的org.slf4j.impl.StaticLoggerBinder类所在的文件路径
在工作路径下,依赖下寻找文件名为:org/slf4j/impl/StaticLoggerBinder.class的文件。其实说白一点,就只寻找各个日志框架的桥接引导类org.slf4j.impl.StaticLoggerBinder,如下是各个日志框架实现的桥接截图:
寻找到对应的日志框架桥接的引导类之后,调用初始化操作完成日志的加载和初始化动作。这就是slf4j门面模式和各日志框架实现的原理
log4j的引导操作截图如下:
在前面的关于log4j的源码浅析(log4j日志框架的使用-CSDN博客)中,log4j的初始化LogManager类中完成的。slf4j的桥接器(StaticLoggerBinder)引导完成初始化加载
log4j2的引导操作截图如下:
在前面的关于log4j2的源码浅析(log4j2日志框架使用-CSDN博客)中,log4j2的入口是LogManager的静态代码块加载。slf4j的桥接器(StaticLoggerBinder)引导完成初始化加载
logback的引导操作可以翻看前面的文章:logback日志框架使用-CSDN博客
各日志框架性能对比
引用一张log4j2的官方性能压测数据图:
log4j2的异步日志性能明显高于log4j和logback(由于日志框架出现的时间有先后,后面的日志肯定会规避前面日志框架的缺点而继承其优点)
log4j2全异步日志开启
1 引入依赖
<dependency><groupId>com.lmax</groupId><artifactId>disruptor</artifactId><version>3.4.2</version>
</dependency>
2 增加启动参数
-Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
或者
System.setProperty("Log4jContextSelector", "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector")
@slf4j注解实现原理
平时在使用slf4j门面日志配合其他日志框架时,很少会在类中通过编码定义Logger对象,而习惯性的使用@slf4j注解完成Logger定义。不知道大家想过没有,这个注解是如何实现的?
@slf4j注解是由lombok
依赖引入的,该依赖会将标注了@slf4j的类编程成形如:
private static final Logger log = LoggerFactory.getLogger(Demo2.class);
的一个log对象
源代码如下:
编译之后的类: