slf4j与Log4j、jdk log、logback的关系及工作方式

本文介绍了slf4j作为日志门面库的角色,以及它如何与log4j、noplogger等具体日志实现库配合工作。slf4j通过静态绑定器StaticLoggerBinder实现与具体日志库的连接,如slf4j-log4j12桥接包用于调用log4j,而slf4j-nop则提供不执行任何日志记录的空实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

 

写在最前面

slf4j是一个门面库

slf4j+具体实现的合作关系

slf4j+log4j的组合

slf4j+noploger


写在最前面

简单地说,在使用slf4j+具体实现的时候,只需要将slf4j-api和对应的桥接jar包放到class路径里面即可。多数项目以maven项目管理包依赖的,例如:

<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>slf4j-api</artifactId>
	<version>1.5.8</version>
</dependency>

<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>slf4j-log4j12</artifactId>
	<version>1.5.8</version>
</dependency>

上面配置代表自动使用log4j日志实现类,因此还需要在加上log4j的依赖

<dependency>
	<groupId>log4j</groupId>
	<artifactId>log4j</artifactId>
	<version>1.2.14</version>
</dependency>

以上配置即可开始编程开发,使用org.slf4j.LoggerFactory.getLogger获取到Logger即可,slf4j会自动找到Log4j实现进行工作。下面会进行讲解。

初学java的同学比较容易对上述几种日志相关的库搞混淆,不清楚几者的关系。虽然自己已经从事JAVA开发很久了,实际上也没有彻底弄清楚slf4j是怎么寻找实际日志实现类进行日志打印的。今天心血来潮,看了一下源代码,记录一下。

slf4j是一个门面库

SLF4J,英文原文为Simple Logging Facade for Java,简单日志门面。Facade即Facade模式(也叫做外观模式)的意思,外观模式,一般指一个系统与外部系统进行通信、交互时,所有的动作、命令都通过一个叫做Facade的进行。

实际上JAVA开发者平时提出的面向接口编程也是一种类似的概念。Facade和接口提供一种通信、交互的契约和规范,达到外部系统和实现类、内部系统解耦。slf4j-api即是这样一个类库,这个库中约定了一个日志库应该提供的方法列表,在org.slf4j.Logger接口描述中。外部系统按照这个接口约定进行日志的记录,至于具体使用的是什么日志实现,应用程序无需知道。

slf4j+具体实现的合作关系

这种组合方式要工作,必须需要配置slf4j-api,slf4j-jdk14/slf4j-log4j12/slf4j-nop, 具体log实现库,缺一不可。为什么三个jar包放到一起就可以工作,无需在代码层次在做其他工作。

将三者紧密连接起来的是存在于每一个桥接包中的StaticLoggerBinder类(存在于各个桥接包中),该类是LoggerFactoryBinder接口(存在于slf4j-api)的实现类。因此桥接包值能加载一个。

slf4j+log4j的组合

以slf4j-api+slf4j-log4j12+log4j为例,讲解怎么通过slf4j-api调用到log4j的。

LoggerFactory.getLogger方法具体经过了一下路径:

  1. LoggerFactory类import StaticLoggerBinder类,该StaticLoggerBinder并不在slf4j-api包实现,存在于各个桥接包中。
  2. 应用程序在类路径下面slf4j-log4j12包中找到StaticLoggerBinder类的实现
  3. StaticLoggerBinder实现为单例模式,此类提供了一个log4j的适配类Log4jLoggerFactory,该适配类又会去寻找log4j的实现代码,然后进行包装起来。
  4. 最后通过getLogger得到的logger实际上就是Log4jLoggerFactory实现代码:
    public Logger getLogger(String name) {
        Logger slf4jLogger = null;
        // protect against concurrent access of loggerMap
        synchronized (this) {
            slf4jLogger = (Logger) loggerMap.get(name);
          if (slf4jLogger == null) {
            org.apache.log4j.Logger log4jLogger;
            if(name.equalsIgnoreCase(Logger.ROOT_LOGGER_NAME)) {
               log4jLogger = LogManager.getRootLogger();
            } else {
              log4jLogger = LogManager.getLogger(name);
            }
            slf4jLogger = new Log4jLoggerAdapter(log4jLogger);
            loggerMap.put(name, slf4jLogger);
          }
        }
        return slf4jLogger;
      }

    代码中直接引用了org.apache.log4j.Logger类,因此三者边联系起来了。

作为对比,我们再讲解slf4j+noploger

slf4j+noploger

NOPLogger是slf4j提供的一个默认日志实现(实际上是一个空实现,里面没有做任何日志记录工作,单纯的只是接受日志记录请求并且抛弃)。

  1. LoggerFactory类import StaticLoggerBinder类,该StaticLoggerBinder存在于slf4j-nop包中。
  2. StaticLoggerBinder提供的日志适配器是NOPLoggerFactory类,该类存在于slf4j-api包中

NOPLoggerFactory提供的实现类代码比较短,很直观,他本身在调用getLogger时返回的NOPLogger.NOP_LOGGER类。

NOPLoggerFactory代码如下

public class NOPLoggerFactory implements ILoggerFactory {

    public NOPLoggerFactory() {
        // nothing to do
    }

    public Logger getLogger(String name) {
        return NOPLogger.NOP_LOGGER;
    }

}

再来看看NOP_LOGGER实现


public class NOPLogger extends MarkerIgnoringBase {

    private static final long serialVersionUID = -517220405410904473L;

    /**
     * The unique instance of NOPLogger.
     */
    public static final NOPLogger NOP_LOGGER = new NOPLogger();

    /**
     * There is no point in creating multiple instances of NOPLOgger, 
     * except by derived classes, hence the protected  access for the constructor.
     */
    protected NOPLogger() {
    }

    /**
     * Always returns the string value "NOP".
     */
    public String getName() {
        return "NOP";
    }

    /**
     * Always returns false.
     * @return always false
     */
    final public boolean isTraceEnabled() {
        return false;
    }

    /** A NOP implementation. */
    final public void trace(String msg) {
        // NOP
    }

    /** A NOP implementation.  */
    final public void trace(String format, Object arg) {
        // NOP
    }

    /** A NOP implementation.  */
    public final void trace(String format, Object arg1, Object arg2) {
        // NOP
    }

   // ...省略
}

此类可以比较直观的看到slf的工作模式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值