Java日志学习四:Simple Logging Facade for Java (SLF4J)源码浅析

一.SLF4J

     http://www.slf4j.org/

 

二.SLF4J核心类

  1.  Logger:日志类。
  2. LoggerFactory:负责查找系统里日志的实现,负责创建日志。类似JCL的LogFactory,类似log4j的LogManager。
  3. ILoggerFactory:该接口只有一个getLogger(name)方法。类似log4j的LoggerRepository 。
  4. LoggerFactoryBinder:该接口可以ILoggerFactory getLoggerFactory()。累世log4j的RepositorySelector。
  5. StaticLoggerBinder:实现LoggerFactoryBinder接口。LoggerFactory在查找日志的实现时,会调用StaticLoggerBinder的getSingleton()方法来判断系统里存在的日志实现。

三.Logger初始化

Java日志学习四:Simple Logging Facade for Java (SLF4J)源码浅析_第1张图片

  1. LoggerFactory的getILoggerFactory方法首先执行performInitialization()。
      1. performInitialization调用bind()完成最核心的一段代码:静态查找日志实现类。怎么做的,StaticLoggerBinder.getSingleton(),就这么简单,如果没有异常说明找到了日志实现类,设置INITIALIZATION_STATE为SUCCESSFUL_INITIALIZATION;如果有异常,根据异常信息设置INITIALIZATION_STATE,如果是java.lang.ClassNotFoundException: org.slf4j.impl.StaticLoggerBinder,设置INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;找不到方法异常设置INITIALIZATION_STATE = FAILED_INITIALIZATION。
      2. bind()返回后,performInitialization()方法会再做一些版本检查,即StaticLoggerBinder可以定义一个静态的REQUESTED_API_VERSION字段,表示该StaticLoggerBinder支持的SLF4J版本,如果该版本不在LoggerFactory定义的兼容版本列表中(API_COMPATIBILITY_LIST),SLF4J会打印警告信息,并列出当前LoggerFactory兼容的版本列表。
  2. 执行完performInitialization后根据INITIALIZATION_STATE,返回对应ILoggerFactory实例。如果为SUCCESSFUL_INITIALIZATION返回绑定的StaticLoggerBinder中的ILoggerFactory实例;如果为NOP_FALLBACK_INITIALIZATION(没有找到桥接jar),则返回NOPLoggerFactory,它返回一个单例的NOPLogger实例,该类不会打印任何日志;如果初始化状态为FAILED_INITIALIZATION,抛出IllegalStateException异常;如果初始化状态为ONGOING_INITIALIZATION,则返回SubstituteLoggerFactory类实例,该状态发生在一个线程正在初始化LoggerFactory,而另一个线程已经开始请求获取ILoggerFactory实例,SubstituteLoggerFactory会记录当前请求的Logger名称,然后返回NOPLogger实例。所有这些在LoggerFactory初始化时被忽略的Logger Name会在LoggerFactory初始化成功以后被report出来(在System.err流中打印出来)。
    public static ILoggerFactory getILoggerFactory() {
        if (INITIALIZATION_STATE == UNINITIALIZED) {
          INITIALIZATION_STATE = ONGOING_INITIALIZATION;
          performInitialization();
        }
        switch (INITIALIZATION_STATE) {
          case SUCCESSFUL_INITIALIZATION:
            return StaticLoggerBinder.getSingleton().getLoggerFactory();
          case NOP_FALLBACK_INITIALIZATION:
            return NOP_FALLBACK_FACTORY;
          case FAILED_INITIALIZATION:
            throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
          case ONGOING_INITIALIZATION:
            // support re-entrant behavior.
            // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106
            return TEMP_FACTORY;
        }
        throw new IllegalStateException("Unreachable code");
      }
     
  3. 得到ILoggerFactory后调用ILoggerFactory.getLogger(name)返回Logger实例。如果使用slf4j作为日志实现,则得到一个org.slf4j.impl.SimpleLogger = org.slf4j.impl.SimpleLoggerFactory.getLogger(name)。SimpleLogger 定义了五个日志级别:TRACEDEBUGINFOWARNERROR。SimpleLogger还支持对classpath下的simplelogger.properties配置文件的解析,不过我们好像基本没用到这个。根据以往的经验,都是先从系统属性里查找这些属性,找不到再去simplelogger.properties查找,当然,SimpleLogger 就是这么做的。
      public static final String SYSTEM_PREFIX = "org.slf4j.simpleLogger.";
    
      public static final String DEFAULT_LOG_LEVEL_KEY = SYSTEM_PREFIX + "defaultLogLevel";
      public static final String SHOW_DATE_TIME_KEY = SYSTEM_PREFIX + "showDateTime";
      public static final String DATE_TIME_FORMAT_KEY = SYSTEM_PREFIX + "dateTimeFormat";
      public static final String SHOW_THREAD_NAME_KEY = SYSTEM_PREFIX + "showThreadName";
      public static final String SHOW_LOG_NAME_KEY = SYSTEM_PREFIX + "showLogName";
      public static final String SHOW_SHORT_LOG_NAME_KEY = SYSTEM_PREFIX + "showShortLogName";
      public static final String LOG_FILE_KEY = SYSTEM_PREFIX + "logFile";
      public static final String LEVEL_IN_BRACKETS_KEY = SYSTEM_PREFIX + "levelInBrackets";
      public static final String WARN_LEVEL_STRING_KEY = SYSTEM_PREFIX + "warnLevelString";
     

 

三.定义自己的日志实现

     如果我们想以slf4j作为门面,实现一个自己的日志系统,我们需要一下三点,就这么简单。

  1. MyLogger implements  org.slf4j.Logger。
  2. MyFactory implements org.slf4j.ILoggerFactory。重写MyLogger getLogger()方法。
  3. StaticLoggerBinder implements org.slf4j.spi.LoggerFactoryBinder,这里名称必须是StaticLoggerBinder ,并且提供static getSingleton()方法,并且getLoggerFactory()方法里返回MyFactory 。

      看看log4j是怎么做的。参考slf4j-log4j12-1.7.5.jar源码。slf4j-log4j12-1.7.5.jar pom会依赖log4j。

  1. org.apache.log4j.Logger log4jLogger已经存在。
  2. Log4jLoggerFactory implements org.slf4j.ILoggerFactory。重写了org.apache.log4j.Logger getLogger()方法。返回的是包装了log4jLogger的一个Log4jLoggerAdapter。new Log4jLoggerAdapter(log4jLogger)。
  3. StaticLoggerBinder implements org.slf4j.spi.LoggerFactoryBinder,getLoggerFactory()方法返回Log4jLoggerFactory 。

 

你可能感兴趣的:(logging)