一.SLF4J
http://www.slf4j.org/
二.SLF4J核心类
- Logger:日志类。
- LoggerFactory:负责查找系统里日志的实现,负责创建日志。类似JCL的LogFactory,类似log4j的LogManager。
- ILoggerFactory:该接口只有一个getLogger(name)方法。类似log4j的LoggerRepository 。
- LoggerFactoryBinder:该接口可以ILoggerFactory getLoggerFactory()。累世log4j的RepositorySelector。
- StaticLoggerBinder:实现LoggerFactoryBinder接口。LoggerFactory在查找日志的实现时,会调用StaticLoggerBinder的getSingleton()方法来判断系统里存在的日志实现。
三.Logger初始化
- LoggerFactory的getILoggerFactory方法首先执行performInitialization()。
- 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。
- 在bind()返回后,performInitialization()方法会再做一些版本检查,即StaticLoggerBinder可以定义一个静态的REQUESTED_API_VERSION字段,表示该StaticLoggerBinder支持的SLF4J版本,如果该版本不在LoggerFactory定义的兼容版本列表中(API_COMPATIBILITY_LIST),SLF4J会打印警告信息,并列出当前LoggerFactory兼容的版本列表。
- 执行完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");
}
- 得到ILoggerFactory后调用ILoggerFactory.getLogger(name)返回Logger实例。如果使用slf4j作为日志实现,则得到一个org.slf4j.impl.SimpleLogger = org.slf4j.impl.SimpleLoggerFactory.getLogger(name)。SimpleLogger 定义了五个日志级别:TRACE、DEBUG、INFO、WARN、ERROR。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作为门面,实现一个自己的日志系统,我们需要一下三点,就这么简单。
- MyLogger implements org.slf4j.Logger。
- MyFactory implements org.slf4j.ILoggerFactory。重写MyLogger getLogger()方法。
- 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。
- org.apache.log4j.Logger log4jLogger已经存在。
- Log4jLoggerFactory implements org.slf4j.ILoggerFactory。重写了org.apache.log4j.Logger getLogger()方法。返回的是包装了log4jLogger的一个Log4jLoggerAdapter。new Log4jLoggerAdapter(log4jLogger)。
- StaticLoggerBinder implements org.slf4j.spi.LoggerFactoryBinder,getLoggerFactory()方法返回Log4jLoggerFactory 。