SLF4J源码解析-LoggerFactory(一)

slf4j的含义为Simple logging facade for Java,其为简单的为java实现的日志打印工具,本文则对其源码进行简单的分析

JAVA调用SLF4J

public class Test{
    private static fianl Logger log = LoggerFactory.getLogger(Test.class) ;
    public static void main(String[] args){
        log.debug();
        log.info();
        log.error();
        log.fatal();
    }
}

Logger接口

内部属性概览

final public String ROOR_LOGGER_NAME = "ROOT" ;

public boolean isTraceEnabled();

public void trace(String msg);

....
....

简单的看也就是定义了相应的级别输出方法,比如trace()/info()/error()/debug()等

LoggerFactory内部属性

其为final类型的class。罗列部分属性,具体如下

  //代表日志工具的初始化状态
  static final int UNINITIALIZED = 0;
  static final int ONGOING_INITILIZATION = 1;
  static final int FAILED_INITILIZATION = 2;
  static final int SUCCESSFUL_INITILIZATION = 3;
  static final int NOP_FALLBACK_INITILIZATION = 4;

  //返回的均为NOPLogger类,即不打印任何日志信息
  static SubstituteLoggerFactory TEMP_FACTORY = new SubstituteLoggerFactory();
  static NOPLoggerFactory NOP_FALLBACK_FACTORY = new NOPLoggerFactory();

LoggerFactory#getLogger()-获取日志对象

其为静态方法,源码如下

  public static Logger getLogger(String name) {
    ILoggerFactory iLoggerFactory = getILoggerFactory();
    return iLoggerFactory.getLogger(name);
  }

继续查看下LoggerFactory#getILoggerFactory()方法

LoggerFactory#getILoggerFactory()-获取真实的日志工厂

源码如下

  public static ILoggerFactory getILoggerFactory() {
    //初次获取,初始化状态为0
    if (INITIALIZATION_STATE == UNINITIALIZED) {
      //状态置为1
      INITIALIZATION_STATE = ONGOING_INITILIZATION;
      //进行初始化
      performInitialization();

    }
    switch (INITIALIZATION_STATE) {
    case SUCCESSFUL_INITILIZATION:
      //返回初始化成功的日志对象
      return StaticLoggerBinder.getSingleton().getLoggerFactory();
    case NOP_FALLBACK_INITILIZATION:
      return NOP_FALLBACK_FACTORY;
    case FAILED_INITILIZATION:
      throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
    case ONGOING_INITILIZATION:
      // support re-entrant behavior.
      // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106
      return TEMP_FACTORY;
    }
    throw new IllegalStateException("Unreachable code");
  }

继续观察LoggerFactory#performInitialization()方法

LoggerFactory#performInitialization()-初始化日志操作
  private final static void performInitialization() {
    //检查项目部署的环境即classpath下有无StaticLoggerBinder.class
    singleImplementationSanityCheck();
    //有则开始绑定
    bind();
    if (INITIALIZATION_STATE == SUCCESSFUL_INITILIZATION) {
      //对slf4j支持的版本进行确认
      versionSanityCheck();
   
    }
  }

分别看下LoggerFactory#singleImplementationSanityCheck()方法和LoggerFactory#bind()方法

LoggerFactory#singleImplementationSanityCheck()-特定类存在判断

特定类指的是org/slf4j/impl/StaticLoggerBinder.class。具体源码如下

  private static void singleImplementationSanityCheck() {
    try {
      //获取类加载器
      ClassLoader loggerFactoryClassLoader = LoggerFactory.class
          .getClassLoader();
      //存放特定类的个数,当无相应的资源返回为空集合,但不为null
      Enumeration paths;
      if (loggerFactoryClassLoader == null) {
        paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
      } else {
        paths = loggerFactoryClassLoader
            .getResources(STATIC_LOGGER_BINDER_PATH);
      }
      List implementationList = new ArrayList();
      //对获取org/slf4j/impl/StaticLoggerBinder.class的资源进行遍历
      while (paths.hasMoreElements()) {
        URL path = (URL) paths.nextElement();
        implementationList.add(path);
      }
      //打印成功日志
      if (implementationList.size() > 1) {
        Util.report("Class path contains multiple SLF4J bindings.");
        for (int i = 0; i < implementationList.size(); i++) {
          Util.report("Found binding in [" + implementationList.get(i) + "]");
        }
        Util.report("See " + MULTIPLE_BINDINGS_URL + " for an explanation.");
      }
    } catch (IOException ioe) {
      Util.report("Error getting resources from path", ioe);
    }
  }

主要任务是判断是否存在org/slf4j/impl/StaticLoggerBinder.class,其在为bind()方法作预备调查,此方法目的是打印一些帮助信息。注意此处不建议拥有多个StaticLoggerBinder

LoggerFactory#bind()-绑定获取真实的日志处理类

bind()方法的处理逻辑显得就很有意思了

  private final static void bind() {
    try {
      //获取StaticLoggerBinder单例
      // the next line does the binding
      StaticLoggerBinder.getSingleton();
      INITIALIZATION_STATE = SUCCESSFUL_INITILIZATION;
      emitSubstituteLoggerWarning();
    } catch (NoClassDefFoundError ncde) {
      //对无此类的异常处理
      String msg = ncde.getMessage();
      //如果错误信息含有org/slf4j/impl/StaticLoggerBinder信息则设置初始化状态为4
      if (msg != null && msg.indexOf("org/slf4j/impl/StaticLoggerBinder") != -1) {
        INITIALIZATION_STATE = NOP_FALLBACK_INITILIZATION;
        Util
            .report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\".");
        Util.report("Defaulting to no-operation (NOP) logger implementation");
        Util.report("See " + NO_STATICLOGGERBINDER_URL
            + " for further details.");
      } else {
        //状态为2,并抛出异常
        failedBinding(ncde);
        throw ncde;
      }
    } catch(java.lang.NoSuchMethodError nsme) {
      //对StaticLoggerBinder类无getSingleton()方法做处理
      String msg = nsme.getMessage();
      if (msg != null && msg.indexOf("org.slf4j.impl.StaticLoggerBinder.getSingleton()") != -1) {
        INITIALIZATION_STATE = FAILED_INITILIZATION;
        Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding.");
        Util.report("Your binding is version 1.5.5 or earlier.");
        Util.report("Upgrade your binding to version 1.6.x. or 2.0.x");
      }
      throw nsme;
    } catch (Exception e) {
      failedBinding(e);
      throw new IllegalStateException("Unexpected initialization failure", e);
    }
  }

bind()方法对StaticLoggerBinder#getSingleton()方法做了异常捕获处理,处理逻辑如下:

  1. 对不存在StaticLoggerBinder类的NoClassDefFoundError异常,如果错误信息含有org/slf4j/impl/StaticLoggerBinder信息则不抛出异常,但设置状态为NOP_FALLBACK_INITILIZATION(4);反之则直接抛出异常,并设置状态为FAILED_INITILIZATION(2)

  2. 对存在StaticLoggerBinder类但不存在getSingleton()方法的NoSuchMethodError异常,均抛出异常,并设置状态为FAILED_INITILIZATION(2)

LoggerFactory#versionSanityCheck()-日志版本要求验证

源码如下

  private final static void versionSanityCheck() {
    try {
      //此处为1.6
      String requested = StaticLoggerBinder.REQUESTED_API_VERSION;

      //判断是否与API的版本一致,此处为true
      boolean match = false;
      for (int i = 0; i < API_COMPATIBILITY_LIST.length; i++) {
        if (requested.startsWith(API_COMPATIBILITY_LIST[i])) {
          match = true;
        }
      }
      if (!match) {
        Util.report("The requested version " + requested
            + " by your slf4j binding is not compatible with "
            + Arrays.asList(API_COMPATIBILITY_LIST).toString());
        Util.report("See " + VERSION_MISMATCH + " for further details.");
      }
    } catch (java.lang.NoSuchFieldError nsfe) {
      // given our large user base and SLF4J's commitment to backward
      // compatibility, we cannot cry here. Only for implementations
      // which willingly declare a REQUESTED_API_VERSION field do we
      // emit compatibility warnings.
    } catch (Throwable e) {
      // we should never reach here
      Util.report("Unexpected problem occured during version sanity check", e);
    }
  }

目前的slf4j版本为1.6

小结

slf4j相当于是一个抽象接口,其会判断classpath下是否存在StaticLoggerBinder类,并针对此类进行相应的逻辑处理,于此我们可以判断出,其可以很好的被其他日志API接入,比如logback等

下节内容预告

针对返回状态为SUCCESSFUL_INITILIZATIONNOP_FALLBACK_INITILIZATIONFAILED_INITILIZATIONONGOING_INITILIZATION时,创建的为何种ILoggerFactory,详情见SLF4J源码解析-LoggerFactory(二)

### 回答1: 您好!您可以通过以下步骤下载slf4j-api-1.7.30.jar: 1. 打开https://www.slf4j.org/download.html网站。 2. 在“SLF4J 1.7.30”下面的“Download”栏中,单击“slf4j-api-1.7.30.zip”链接。 3. 下载完成后,解压缩zip文件。 4. 在解压缩的文件夹中,您可以找到“slf4j-api-1.7.30.jar”文件,将其复制到您的项目中即可。 希望这可以帮助您! ### 回答2: 要下载slf4j-api-1.7.30.jar,可以按照以下步骤进行: 1. 打开您常用的浏览器,如谷歌浏览器或火狐浏览器等。 2. 在搜索引擎中输入"slf4j-api-1.7.30.jar下载",然后按下Enter键进行搜索。 3. 浏览器会列出相关的搜索结果页面,您可以选择其中一个可靠的网站,如官方网站或Maven仓库等。 4. 进入您选择的网站后,在网站的搜索框中输入"slf4j-api-1.7.30.jar",然后点击搜索按钮或按下Enter键。 5. 网站会列出与您搜索关键词相关的文件。找到"slf4j-api-1.7.30.jar"文件并点击下载链接。 6. 系统会提示您选择文件的保存位置。您可以选择将其保存在您电脑中合适的文件夹中,以便于稍后安装或使用。 7. 等待文件下载完成。下载速度取决于您的网络连接速度。 8. 下载完成后,您可以在指定的文件夹中找到"slf4j-api-1.7.30.jar"文件。 请注意,确保下载文件的来源可靠和安全,并且与您的操作系统兼容。 ### 回答3: slf4j-api-1.7.30.jar 是一个用于Java应用程序的日志框架的jar文件。它是Simple Logging Facade for Java (SLF4J)的API模块,用于将不同的日志实现与应用程序代码分离。通过使用SLF4J,可以在应用程序中编写一致的日志记录代码,而不依赖于特定的日志实现。 下载 slf4j-api-1.7.30.jar 可以通过多种途径实现。其中一种方法是在SLF4J的官方网站上下载。访问官方网站后,找到下载页并选择相应的版本进行下载。另外,也可以通过Maven等构建工具进行下载。在项目的pom.xml文件中指定 slf4j-api 的依赖,构建工具会自动下载并管理相关的jar文件。 下载后,将 slf4j-api-1.7.30.jar 添加到项目的构建路径中。这样,在编写日志记录代码时,就可以使用SLF4J提供的API进行日志记录,而不需要关注具体的日志实现。SLF4J支持多种日志实现,如Logback、Log4j等,可以根据需要选择合适的实现,并将其相应的jar文件添加到项目中。 总结来说,下载 slf4j-api-1.7.30.jar 是为了在Java应用程序中使用SLF4J日志框架。下载后,将其添加到项目的构建路径中,然后可以使用SLF4J的API进行日志记录,而无需直接依赖于特定的日志实现。这样可以方便地对日志框架进行切换和管理,提高代码的可维护性和灵活性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值