SLF4j:Log facade abstract

jopen 8年前發布 | 11K 次閱讀 Java 日志處理

內 容:

  • 應用中使用slf4j的工作流程
  • 簡單示例
  • ILoggerFactory實例化過程
  • 由ILoggerFactory創建Logger實例
  • slf4j 適配器實現
  • 自定義適配器

現如今,日志框架層出不窮,JDKLogger、Log4j、Logback等這些是最常用的了。然而現在越來越多的框架中,都會在使用日志框架的同時,還會使用到一個門面(slf4j-api.jar),使用這個門面的的最方便的地方大抵是它提供格式化字符串的功能。

slf4j 與其他日志框架的關系

在應用程序中,直接使用slf4j-api.jar就可以完成日志的記錄,而不用在代碼里直接使用某一種日志框架了(雖然最終記錄日志還是有日志框架來完成的)。

下面是使用了slf4j時,應用程序、slf4j、slf4j-adapter.jar、日志框架之間的調用關系:

下面是一個簡單的示例:

package com.fjn.frame.slf4j;

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");
   }
}

LoggerFactory.getLogger(xxx)要分為兩個過程:

1、實例化ILoggerFactory, 這個步驟只是在第一次進行。

2、根據ILoggerFactory實例創建Logger實例。

下面就分別來說說這兩個過程:

ILoggerFactory 實例化的過程

在使用slf4j時,并不需要指定具體使用哪種日志框架,只需要給定相關的適配器包就可以了。那么如何拿到真正的ILoggerFactory實現,并實例化的呢?

1、在LogFactory的classloader的搜索路徑下查找” org/slf4j/impl/StaticLoggerBinder.class ” 類

private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";

  private static void singleImplementationSanityCheck() {
    try {
      ClassLoader loggerFactoryClassLoader = LoggerFactory.class
          .getClassLoader();
      Enumeration paths;
      if (loggerFactoryClassLoader == null) {
        paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
      } else {
        paths = loggerFactoryClassLoader
            .getResources(STATIC_LOGGER_BINDER_PATH);
      }
      // use Set instead of list in order to deal with  bug #138
      // LinkedHashSet appropriate here because it preserves insertion order during iteration
      Set implementationSet = new LinkedHashSet();
      while (paths.hasMoreElements()) {
        URL path = (URL) paths.nextElement();
        implementationSet.add(path);
      }
      if (implementationSet.size() > 1) {
        Util.report("Class path contains multiple SLF4J bindings.");
        Iterator iterator = implementationSet.iterator();
        while(iterator.hasNext()) {
          URL path = (URL) iterator.next();
          Util.report("Found binding in [" + path + "]");
        }
        Util.report("See " + MULTIPLE_BINDINGS_URL + " for an explanation.");
      }
    } catch (IOException ioe) {
      Util.report("Error getting resources from path", ioe);
    }
  }

如果有多個就會打印:

2、將slf4j與指定的實現進行綁定,這一步的操作,通常是:

1)單實例化StaticLoggerBinder。

2)檢查StaticLoggerBinder的版本,其實就是需要有一個靜態的非final的變量(這個變量不是必須得有的),

StaticLoggerBinder. REQUESTED_API_VERSION

3、獲取到ILoggerFactory的實例

一般來說,是返回一個static ILoggerFactory impl=new   XXXLoggerFactory();

由ILoggerFactory來創建Logger實例

LoggerFactory創建Logger實例,其實由日志框架本身的LogManager創建一個Logger,然后包裝成LoggerAdapter。例如Log4j的適配包中的Log4jLoggerFactory#getLogger(String name)的實現如下:

public Logger getLogger(String name) {
    Logger slf4jLogger = loggerMap.get(name);
    if (slf4jLogger != null) {
      return slf4jLogger;
    } else {
      org.apache.log4j.Logger log4jLogger;
      if(name.equalsIgnoreCase(Logger.ROOT_LOGGER_NAME))
        log4jLogger = LogManager.getRootLogger();
      else
        log4jLogger = LogManager.getLogger(name);

      Logger newInstance = new Log4jLoggerAdapter(log4jLogger);
      Logger oldInstance = loggerMap.putIfAbsent(name, newInstance);
      return oldInstance == null ? newInstance : oldInstance;
    }
  }

下面用是一張簡易的關系圖,顯示了適配器的實現:

自定義日志框架適配器

在一些公司,肯定還有自己的Logger框架,如果也希望通過slf4j來做日志,就需要寫相關的適配器包了。通過上述的兩個過程的了解,很容易就能知道如何自定義適配器了。

自定義適配器中,必須包括3個組件:

· StaticLoggerBinder

這個類需要遵守下列規約:

1)  類名必須是org.slf4j.impl.StaticLoggerBinder

2)  這個類必須是單例的,必須有getSingleton()方法

3)  盡可能的有 public static String REQUESTED_API_VERSION 字段,并且不能是final的。

4)  要實現org.slf4j.spi.LoggerFactoryBinder接口。

· LoggerFactoryImpl

這個類要實現org.slf4j.ILoggerFactory接口

· LoggerAdapter

這個類要實現org.slf4j.Logger接口。

來自: http://www.cnblogs.com/f1194361820/p/5096014.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!