slf4j是一个facade门面,并不设计具体的日志输出。下面举个例子说明:
先假设你知道log4j或者其他日志工具有个打印日志的方法logger.info(msg),如果直接使用log4j或者其他日志工具,只需要在需要打印日志的时候调用其logger.info(msg),这里的logger对象是属于log4j或者其他实际打印日志的工具。
问题来了,假如我们代码已经使用log4j的logger对象打印日志,当项目变化时想要改用其他日志工具比如jui或者logback等等,这时候不单是把log4j的jar包换成其他的,还要找出所有log4j打印日志的方法全部用其他工具方法改写,对于切换日志工具来说及其繁琐。而且,项目的变化和技术的变化可能就带来这种日志工具的改变。
slf4j为日志工具切换提供解决方案:

如上图所示,最顶层的slf4j-api门面提供了一套打印日志的API规范,比如slf4jLogger.info("msg"),最底层是某个日志工具比如log4j的打印日志的具体实现,而中间是slf4j和log4j两者的适配器,这个适配器所作的工作大概如下伪代码所示:
public void info1(String msg){
//调用slf4j-log4j的适配器
log4j_adapter.info2(msg);
}
/*
* 适配器把slf4j API方法的参数调整为符合log4j的参数,
* 然后调用log4j的方法打印日志
*/
public void info2(String msg){
//参数的处理和转换、适配
String message = doSomething(msg);
//调用log4j方法真正打印
log4jLogger.info3(message);
}
如上代码所示,
(1)info1方法是slf4j提供的规范,系统所有日志打印都直接使用这套API规范。
(2)而到了确定使用某种日志工具打印时,比如log4j,我们就引入log4j_adapter适配器的jar包,然后再引入log4j日志工具,info1方法调用适配器时是使用接口绑定的,而最终调用会根据引入的适配器jar包决定,这就是使用适配器层的好处,不管想要使用哪种日志工具,只要把它的适配器jar包引入,这时适配器接口就会找到它的实现类也就是引入的适配器实现类。也因此,适配器层jar只能引入一种。
(3)slf4j支持的所有日志工具都写好了对应的适配器层jar包,作用是为slf4j的方法和具体的日志方法做桥接。正是因为适配器的转换,才使得slf4j能够向外提供统一的日志打印方法。
(4)具体的日志工具还是要配置的,比如log4j的配置,只是代码中不直接使用具体的打印日志方法,而是使用统一的slf4j规范的方法。
slf4j-api本身的代码非常少,只是一套打印日志方法的规范,slf4j的重点应该是与具体日志工具如何适配的代码。
slf4j日志的具体使用:
(1)首先是比如info()、error()这些方法的使用,{}在这些方法的msg中被当成标识符,比如logger.error("this {} a {}!", "is", "pen")中的两个{}将被后面的参数替换,而且每次日志打印之前都会先判断是否有打印权限,有才进行参数替换。
(2)具体使用可以参考官方日志
https://www.slf4j.org/manual.html
https://www.slf4j.org/faq.html#logging_performance
总结:slf4j日志系统应该是重在原理的理解上,涉及到门面、适配器、包装等设计模式,具体实现并不难可直接参考源码。
SLF4J是一个日志门面,提供统一的日志API,允许用户在运行时绑定不同的日志实现,如log4j或logback。它通过适配器层实现与具体日志工具的桥接,简化了日志工具的切换。SLF4J的使用包括调用info()、error()等方法,并利用{}进行参数替换。了解其设计模式如门面和适配器对于理解和应用SLF4J至关重要。
2391

被折叠的 条评论
为什么被折叠?



