SLF4J,即简单日志门面(Simple Logging Facade for Java),不是具体的日志解决方案,它只服务于各种各样的日志系统。按照官方的说法,SLF4J是一个用于日志系统的简单Facade,允许最终用户在部署其应用时使用其所希望的日志System,
Logger log = LoggerFactory.getLogger(getClass());
LoggerFactory 是一个final 类 也是一个日志工厂类 生产 Logger 对象,看看getLogger 方法
public static Logger getLogger(Class clazz) {
return getLogger(clazz.getName());
}
public static Logger getLogger(String name) {
ILoggerFactory iLoggerFactory = getILoggerFactory();
return iLoggerFactory.getLogger(name);
}
public static ILoggerFactory getILoggerFactory() {
//假如是未初始化状态
if (INITIALIZATION_STATE == UNINITIALIZED) {
//初始化状态为 正在进行中
INITIALIZATION_STATE = ONGOING_INITIALIZATION;
//进入performIntialization 方法初始化!
performInitialization();
}
switch (INITIALIZATION_STATE) {
//假如初始化成功
case SUCCESSFUL_INITIALIZATION:
//获取具体的日志工厂对象
return StaticLoggerBinder.getSingleton().getLoggerFactory();
case NOP_FALLBACK_INITIALIZATION:
// 返回NOPLoggerFactory 日志工厂
return NOP_FALLBACK_FACTORY;
case FAILED_INITIALIZATION:
//初始化失败 抛出异常
throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
case ONGOING_INITIALIZATION:
// 返回 SubstituteLoggerFactory 日志工厂
return TEMP_FACTORY;
}
throw new IllegalStateException("Unreachable code");
}
private final static void performInitialization() {
//绑定一个具体的日志实现
bind();
if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) {
//检查日志的版本
versionSanityCheck();
}
}
private final static void bind() {
try {
//寻找日志绑定实现类,如果找不到或者指定的方法不存在,都会报错提示,实现类可能有多个,
//因此用Set集合
Set staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
//报告打印
reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
// 测试是否存在 getSingleton 方法
StaticLoggerBinder.getSingleton();
// 设置初始化状态,初始化成功
INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
//报告打印实际的绑定类型
reportActualBinding(staticLoggerBinderPathSet);
emitSubstituteLoggerWarning();
//如果找不到指定的类
} catch (NoClassDefFoundError ncde) {
//获取异常信息
String msg = ncde.getMessage();
//报告异常信息
if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {
INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
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 {
failedBinding(ncde);
throw ncde;
}
//如果找不到指定的方法 也就是 getSingleton 方法
} catch (java.lang.NoSuchMethodError nsme) {
String msg = nsme.getMessage();
if (msg != null && msg.indexOf("org.slf4j.impl.StaticLoggerBinder.getSingleton()") != -1) {
INITIALIZATION_STATE = FAILED_INITIALIZATION;
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.");
}
throw nsme;
} catch (Exception e) {
failedBinding(e);
throw new IllegalStateException("Unexpected initialization failure", e);
}
}
寻找绑定实现类
private static Set findPossibleStaticLoggerBinderPathSet() {
Set staticLoggerBinderPathSet = new LinkedHashSet();
try {
//获取LoggerFactory的类加载器
ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
Enumeration paths;
//假如LoggerFactory的类加载器为空
if (loggerFactoryClassLoader == null) {
//如果获取不到类加载器则说明是系统加载器,那么在系统路径下获取该资源文件
paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
} else {
//获取到了类加载器,则用该类加载器加载指定的资源文件
paths = loggerFactoryClassLoader
.getResources(STATIC_LOGGER_BINDER_PATH);
}
while (paths.hasMoreElements()) {
URL path = (URL) paths.nextElement();
//将地址加入到集合中去
staticLoggerBinderPathSet.add(path);
}
} catch (IOException ioe) {
Util.report("Error getting resources from path", ioe);
}
return staticLoggerBinderPathSet;
}
通过以上代码 找到了默认的 日志绑定实现类 StaticLoggerBinder,在通过该绑定类来获取Log4jLoggerFactory 具体的日志工厂对象
private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
//单例
public static final StaticLoggerBinder getSingleton() {
return SINGLETON;
}
private StaticLoggerBinder() {
loggerFactory = new Log4jLoggerFactory();
try {
Level level = Level.TRACE;
} catch (NoSuchFieldError nsfe) {
Util
.report("This version of SLF4J requires log4j version 1.2.12 or later. See also http://www.slf4j.org/codes.html#log4j_version");
}
}
// 获取 Log4jLoggerFactory 类 对象
public ILoggerFactory getLoggerFactory() {
return loggerFactory;
}
在看看 Log4jLoggerFactory 类的 实现,Log4jLoggerFactory类 是对 ILoggerFactory接口的实现
ILoggerFactory 只定义了一个方法
public interface ILoggerFactory {
public Logger getLogger(String name);
}
public class Log4jLoggerFactory implements ILoggerFactory {
ConcurrentMap<String, Logger> loggerMap;
public Log4jLoggerFactory() {
loggerMap = new ConcurrentHashMap<String, Logger>();
}
public Logger getLogger(String name) {
//查看是否存在key 为 name 的 Logger 对象
Logger slf4jLogger = loggerMap.get(name);
if (slf4jLogger != null) {
return slf4jLogger;
} else {
//这才是具体的日志实现
org.apache.log4j.Logger log4jLogger;
//获取log4jLogger 类对象
if(name.equalsIgnoreCase(Logger.ROOT_LOGGER_NAME))
log4jLogger = LogManager.getRootLogger();
else
log4jLogger = LogManager.getLogger(name);
//Log4jLoggerAdapter 是一个适配器类 用于适配Logger 接口
//因为 Log4jLoggerAdapter 继承自 MarkerIgnoringBase 类
//而 MarkerIgnoringBase 类 又实现了 Logger 接口
// 所有的底层都是 log4jLogger 去实现的
Logger newInstance = new Log4jLoggerAdapter(log4jLogger);
Logger oldInstance = loggerMap.putIfAbsent(name, newInstance);
return oldInstance == null ? newInstance : oldInstance;
}
}
}
总结
Slf4j 主要用到了 JVM类加载机制 门面设计模式 适配器设计模式
简单的说下它的原理,就是通过工厂类,提供一个用户的接口!用户可以通过这个外观接口,直接使用API实现日志的记录。而后面的具体实现由Slf4j来寻找加载.寻找的过程,就是通过类加载加载那个叫org/slf4j/impl/StaticLoggerBinder.class的文件,只要实现了这个文件的日志实现系统,都可以作为一种实现方式。如果找到很多种方式,那么就寻找一种默认的方式