(1). 概述

对于slf4j一直都是偏于简单的使用,而,我个人性格是偏向于:知其然,知其所以然,这个世界,人都是一直处理变化中,而技术也会不断的迭代来着的.

(2). slf4j入口在哪?

slf4j源码的入口在:LoggerFactory类上(注意:此次分析的源码为1.7,1.8之后有一些新的变化.)

package org.slf4j;

public final class LoggerFactory {
	
	// 1. getLogger通过:ILoggerFactory创建:Logger
	// 典型的工厂模式
	public static Logger getLogger(String name) {
		ILoggerFactory iLoggerFactory = getILoggerFactory();
		return iLoggerFactory.getLogger(name);
	} // end getLogger
}	

(3). 获取日志工厂(getILoggerFactory)

public static ILoggerFactory getILoggerFactory() {
	if (INITIALIZATION_STATE == UNINITIALIZED) {
		synchronized (LoggerFactory.class) {
			if (INITIALIZATION_STATE == UNINITIALIZED) {
				INITIALIZATION_STATE = ONGOING_INITIALIZATION;
				// *****************************************************************
				// 准备初始化
				// *****************************************************************
				performInitialization();
			}
		}
	}
	switch (INITIALIZATION_STATE) {
	case SUCCESSFUL_INITIALIZATION:
	    // *****************************************************************
		// 很好奇为什么是通过静态创建工厂?
		// 细细去剖析:当slf4j在打包(mvn)时,会排除该类:StaticLoggerBinder
		// 而logback包里会写这样一个类,这也太粗爆了吧! 
		// 另一个疑问来了:为什么不用SPI?切换源码到最新分支时,发现在1.8是通过SPI来做的了.
		// *****************************************************************
		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://jira.qos.ch/browse/SLF4J-97
		return SUBST_FACTORY;
	}
	throw new IllegalStateException("Unreachable code");
} // end getILoggerFactory

"logback实现slf4j"

(4). performInitialization

private final static void performInitialization() {
	bind();
	if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) {
		versionSanityCheck();
	}
}

(5). bind

private final static void bind() {
	try {
		Set<URL> staticLoggerBinderPathSet = null;
		if (!isAndroid()) {
			// ***************************************************************
			// 通过ClassLoader加载:org/slf4j/impl/StaticLoggerBinder.class
			// ***************************************************************
			staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
			reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
		}
		// the next line does the binding
		StaticLoggerBinder.getSingleton();
		INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
		reportActualBinding(staticLoggerBinderPathSet);
	} 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;
		}
	} catch (java.lang.NoSuchMethodError nsme) {
		String msg = nsme.getMessage();
		if (msg != null && msg.contains("org.slf4j.impl.StaticLoggerBinder.getSingleton()")) {
			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);
	} finally {
		postBindCleanUp();
	}
} // end bind

(6). findPossibleStaticLoggerBinderPathSet

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

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

(7). 总结

slf4j的设计有点粗爆,也就是说那些slf4j的实现(或者桥接jar),肯定会存在org/slf4j/impl/StaticLoggerBinder类,瞬间就不想看下去了.