揭祕,門面日誌如何發現具體日誌組件

commons-logging

commons-logging是apache提供的一個通用的日誌接口,是爲了不和具體的日誌方案直接耦合的一種實現。經過commons-logging用戶能夠本身選擇log4j或者jdk自帶的logging做爲具體實現。html

使用commons-logging的代碼以下java

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


public class MyApplication {
  private Log log = LogFactory.getLog(this.getClass());
}

複製代碼

Log是一個接口,LogFactory的內部回去裝載具體的日誌系統,並得到實現該Log接口的實現類,其具體流程以下apache

  1. 經過系統屬性org.apache.commons.logging.LogFactory加載LogFactory的實現
  2. 若是未找到,則經過服務發現機制(SPI)在META-INF/services/org.apache.commons.logging.LogFactory尋找實現類進行加載
  3. 若是未找到,則從classpath下尋找commons-logging.properties文件,根據文件中org.apache.commons.logging.LogFactory配置進行加載
  4. 若是仍未找到,則使用默認配置:若是找到Log4j 則默認使用log4j 實現,若是仍沒有則使用JDK14Logger 實現,再沒有則使用commons-logging 內部提供的SimpleLog 實現

因此只要你引入了log4j的jar包以及對其進行了配置底層就會直接使用log4j來進行日誌輸出了,其實質就是在org.apache.commons.logging.impl.Log4JLogger(commons-logging包)的getLogger方法調用了log4j的Logger.getLogger來返回底層的Logger,當記錄日誌的時候就會經過這個Logger寫日誌。bash

Slf4j

slf4j全稱爲Simple Logging Facade for JAVA,java簡單日誌門面。其使用方式以下框架

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyApplication {
  private Logger logger = LoggerFactory.getLogger(this.getClass());
}

複製代碼

slf4j和commons-logging不同的是,若是你沒有具體的日誌組件(logback,log4j等),它是沒法打印日誌的,若是你在一個maven項目裏面只引入slf4j的jar包,而後記錄日誌maven

public class Main {

  public static Logger logger = LoggerFactory.getLogger(Main.class);

  public static void main(String[] args) {
      logger.info("slf4j");
      System.out.println("done");
  }

}


複製代碼

就會出現下面的信息this

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.
複製代碼

若是你此時引入log4j或者logback的jar包就會打印出日誌。spa

經過LoggerFactory.getLogger()查看其實現原理,其加載Logger核心源碼以下:日誌

static Set<URL> findPossibleStaticLoggerBinderPathSet() {
  
  Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>();
  try {
      ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
      Enumeration<URL> paths;
      if (loggerFactoryClassLoader == null) {
          paths = ClassLoader.getSystemResources("org/slf4j/impl/StaticLoggerBinder.class");
      } else {
          paths = loggerFactoryClassLoader.getResources("org/slf4j/impl/StaticLoggerBinder.class");
      }
      while (paths.hasMoreElements()) {
          URL path = paths.nextElement();
          staticLoggerBinderPathSet.add(path);
      }
  } catch (IOException ioe) {
      Util.report("Error getting resources from path", ioe);
  }
  return staticLoggerBinderPathSet;
}

複製代碼

其主要思想就是去classpath下找org/slf4j/impl/StaticLoggerBinder.class,即全部slf4j的實現,不管是log4j仍是logback都有實現類,同窗們能夠看下本身項目中的jar包。code

若是引入了多個實現,編譯器會在編譯的時候選擇其中一個實現類進行綁定,也會將具體綁定的哪一個日誌框架告訴你

private static void reportActualBinding(Set<URL> binderPathSet) {
  
    if (binderPathSet != null && binderPathSet.size() > 1) {
        Util.report("Actual binding is of type [" + StaticLoggerBinder.getSingleton().getLoggerFactoryClassStr() + "]");
    }
}

複製代碼
相關文章
相關標籤/搜索