前言
slf4j是门面模式的典型应用。
我们为什么要使用slf4j,举个例子:
我们自己的系统中使用了slf4j-log4j12这个日志系统
我们的系统使用了A.jar,A.jar中使用的日志系统为JCL+JUL
这样,我们的系统就不得不同时支持并维护log4j、JUL2种日志框架,非常不便。
解决这个问题的方式就是引入一个适配层,由适配层决定使用哪一种日志系统,而调用端只需要做的事情就是打印日志而不需要关心如何打印日志,slf4j或者commons-logging就是这种适配层,slf4j是本文研究的对象。
从上面的描述,我们必须清楚地知道一点:slf4j只是一个日志标准,并不是日志系统的具体实现。理解这句话非常重要,slf4j只做两件事情:
提供日志接口
提供获取具体日志对象的方法
slf4j-simple、logback都是slf4j的具体实现,log4j并不直接实现slf4j,但是有专门的一层桥接slf4j-log4j12来实现slf4j。
在解决这个问题前,我们先学习下slf4
一、核心包
SLF4J的核心包是slf4j-api
,本文使用的是1.7.30
版本
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
public class App {
private static Logger logger = LoggerFactory.getLogger(App.class);
public static void main( String[] args ) {
logger.info("1");
}
}
//SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
//SLF4J: Defaulting to no-operation (NOP) logger implementation
//SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
slf4j他也不记录日志,通过绑定器绑定一个具体的日志记录来完成日志记录
因为在您的类路径上找不到slf4j绑定器,所以将打印此警告
二、绑定器
作用:绑定一个具体的日志记录来完成日志记录
常用绑定器如下
slf4j-log4j12: log4j绑定器,其底层依赖log4j12包,所以我们不要重新导入log4j12
slf4j-jdk14: JUL绑定器
slf4j-simple: simple-log绑定器
slf4j-jcl: JCL绑定器,其底层依赖jcl包,所以我们不要重新导入jcl
本文使用的是log4j绑定器slf4j-log4j12
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.30</version>
</dependency>
注意要和核心包的版本一样
public class App {
private static Logger logger = LoggerFactory.getLogger(App.class);
public static void main( String[] args ) {
logger.info("1");
}
}
//输出:2020 04 09 12:40:50-INFO main learnning.App -learnning.App.main(App.java:19) 1
三 、桥接器
常用桥接器如下:
1、jcl-over-slf4j
作用:将JCL日志系统桥接到slf4j日志系统,底层重写了JCL
现在有一个需求:
我们自己的系统中使用了slf4j-log4j12这个日志系统
我们的系统使用了A.jar,A.jar中使用的日志系统为JCL+JUL
这样,我们的系统就不得不同时支持并维护log4j、JUL2种日志框架,非常不便。
怎么解决这个问题呢?
这时候SLF4J桥接器就登场了,利用桥接器,我们可以使别的日志系统桥接到SLF4J。
这样的话,我们项目就统一了使用log4j日志系统了
2、jul-to-slf4j
作用:将JUL日志系统桥接到slf4j日志系统
注意:与其他桥接模块(分别重新实现JCL和log4j的jcl-over-slf4j和log4j-over-slf4j)相反,jul-to-slf4j模块不会重新实现java.util.logging
,因为java下的软件包。*名称空间无法替换。相反,jul-to-slf4j会将LogRecord 对象转换为它们的SLF4J等效项。请注意LogRecord ,无论是否为给定级别禁用了SLF4J记录器,此转换过程都会产生构建实例的成本。因此,从Jul到SLF4J的转换会严重增加禁用日志记录语句的成本(60倍或6000%),并显着影响已启用日志语句的性能(总体增加20%)。 随着版本的logback 0.9.25,它可以完全消除的帮助下禁用日志报表的60倍转换开销LevelChangePropagator。
如果您担心应用程序的性能,则SLF4JBridgeHandler仅当满足以下两个条件之一时才适合使用 :
几乎没有日志记录语句
LevelChangePropagator 已安装
3、log4j-over-slf4j
作用:将log4j日志系统桥接到slf4j日志系统,底层重写了log4j
现系统日志是slf4j+jul,而我们引用的A包使用的log4j,那我们怎么统一日志系统为jul
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
log4j-over-slf4j包重写了log4j,这时候我只需要导入log4j-over-slf4j包。
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.30</version>
</dependency>
注意:log4j包删与不删不会影响这个关系。
三、注意事项
请注意,不能同时部署同种日志的桥接器和连接器
如:不能同时部署jcl-over-slf4j.jar和 slf4j-jcl.jar。前一个jar文件将使JCL将日志记录系统的选择委派给SLF4J,后一个jar文件将使SLF4J将日志记录系统的选择委派给JCL,从而导致无限循环。