SLF4J是Simple Logging Facade For Java的缩写,从名字中的Facade可以看出它是一个门面。SLF4J并不是一个具体实现,而是一个日志框架,或者说日志框架的抽象,可以在程序运行时,更新Classpath中的jar包加载具体的日志实现,比如说log4j、logback。这个具体的实现可以称之为binding
SINCE 1.6.0
如果没有在classpath中发现binding,那么SLF4J不会做任何操作
SINCE 1.7.0
接口Logger支持接受多种参数的方法,以替代Object[],它需要只是JDK1.5以上的版本。多种参数变量将在Java编译器后台被装换成object[],因此编译器生成的接口在1.7x 和1.6.x中是无法区分的,因此1.7.x是完全100%兼容1.6.x的。
SINCE 1.7.5
日志索引时间得到了显著的提升,建议用户使用SLF4J 至少1.7.5以后的版本。
SINCE 1.7.9
通过将slf4j.detectLoggerNameMismatch系统属性设置为true,SLF4J可以自动发现名称错误的记录器。
SINCE 2.0.0
SLF4J 2.0.0 API依赖了JDK8,并且提供了向后兼容的流式API。因为向后兼容性,所以现有的日志框架不需要做任何修改就可以实现使用流式API了。
按照编程传统,下面是一个使用SLF4J输出“Hello World”的最简代码段。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(HelloWorld.class);
logger.info("Hello World");
}
}
编译、运行HelloWorld将在控制台输出以下内容。
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.
上面的warning,说明了没有在classpath中找到slf4j binding,将slf4j-simple-1.7.28.jar加入classpath中即可输出如下的正确结果
0 [main] INFO HelloWorld - Hello World
下面的代码展示了SLF4J典型的使用模式。注意第15行占位符{}
的使用方式。请尽量使用占位符的方式来代替字符串拼接,这样可以避免多余的计算,显著提高框架的性能。
1: import org.slf4j.Logger;
2: import org.slf4j.LoggerFactory;
3:
4: public class Wombat {
5:
6: final Logger logger = LoggerFactory.getLogger(Wombat.class);
7: Integer t;
8: Integer oldT;
9:
10: public void setTemperature(Integer temperature) {
11:
12: oldT = t;
13: t = temperature;
14:
15: logger.debug("Temperature set to {}. Old temperature was {}.", t, oldT);
16:
17: if(temperature.intValue() > 50) {
18: logger.info("Temperature has risen above 50 degrees.");
19: }
20: }
21: }
这个想法是使用LoggingEventBuilder逐段构建日志事件,并在事件完全构建后进行日志记录。atTrace()
,atInfo()
,atWarn()
和atError()
方法都是org.slf4j.Logger接口中的新方法,它将返回一个LogginEventBuilder,在disable级别的日志level,这个方法不会做任何的事情,这是一个纳秒级别的优化。
下面是一些用法示例:
logger.atInfo().log("Hello world");
// 等同于
logger.info("Hello world.");
下面的语句在功能上等同与以前接口
int newT = 15;
int oldT = 16;
// using traditional API
logger.debug("Temperature set to {}. Old temperature was {}.", newT, oldT);
// using fluent API, add arguments one by one and then log message
logger.atDebug().addArgument(newT).addArgument(oldT).log("Temperature set to {}. Old temperature was {}.");
// using fluent API, log message with arguments
logger.atDebug().log("Temperature set to {}. Old temperature was {}.", newT, oldT);
// using fluent API, add one argument and then log message providing one more argument
logger.atDebug().addArgument(newT).log("Temperature set to {}. Old temperature was {}.", oldT);
// using fluent API, add one argument with a Supplier and then log message with one more argument.
// Assume the method t16() returns 16.
logger.atDebug().addArgument(() -> t16()).log(msg, "Temperature set to {}. Old temperature was {}.", oldT);
前面提到了SLF4J支持多种日志框架,在SLF4J发布的时候,会一起发布多种SLF4J binding jar,每一种binding都可以实现SLF4J到一个具体日志实现的绑定。
类库和组件的作者应该针对SLF4J接口进行编码,这样终端用户就可以通过classpath中的jar包,选择自己的需要选择日志框架。这是一种简单并且行之有效的办法。
基本规则:内嵌式的组件、类库应该避免声明依赖任何SLF4J binding,仅仅依赖slf4j-api就够了。
LOGBACK-CLASSES
如果你使用loback-classic作为底层日志框架,你只需要像下面示例代码一样,在pom.xml中声明就可以了,它会将logback-core-1.2.3.jar以及slf4j-api-1.7.28.jar都添加到项目中。
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
LOG4J
如果你想要使用log4j作为底层日志框架实现,那么你需要在pom.xml中声明"org.slf4j:slf4j-log4j12-1.7.28.jar"就可以了。他将引入slf4j-log4j12-1.7.28.jar, slf4j-api-1.7.28.jar log4j-1.2.17.jar 到你的项目中。
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.28</version>
</dependency>
从客户的角度来讲,所有版本的slf4j-api都是兼容的。slf4j-api-N能够和slf4j-api-M完全的兼容,因此不需要担心有太多slf4j-api的依赖。 但是一定需要关注和保证binding。 binding需要和slf4j-api匹配。
有时候,你的工程依赖了各种不同的组件,而这些组件并没有使用slf4j,可能是common log、log4j等。slf4j为提供了bridging解决这种场景
原文:https://www.cnblogs.com/xuerge/p/slf4j-yong-hu-shi-yong-shou-ce.html