public abstract class LogFactory {
public static Log getLog(Class clazz) throws LogConfigurationException {
// 默认实现类为LogFactoryImpl
return getFactory().getInstance(clazz);
}
}
利用LogFactoryImpl实例化具体的日志框架。其中,如果存在log4j依赖则选择Log4JLogger,Jdk14Logger是指JDK本身集成的JUL,否则使用JCL本身自带的日志实现之SimpleLog。
public class LogFactoryImpl extends LogFactory {
protected Constructor logConstructor = null;
private static final String[] classesToDiscover = {
"org.apache.commons.logging.impl.Log4JLogger",
"org.apache.commons.logging.impl.Jdk14Logger",
"org.apache.commons.logging.impl.Jdk13LumberjackLogger",
"org.apache.commons.logging.impl.SimpleLog"
}
protected Log newInstance(String name) throws LogConfigurationException {
Log instance;
if (logConstructor == null) {
instance = discoverLogImplementation(name);
}else {
Object params[] = { name };
instance = (Log) logConstructor.newInstance(params);
}
if (logMethod != null) {
Object params[] = { this };
logMethod.invoke(instance, params);
}
return instance;
}
private Log discoverLogImplementation(String logCategory)throws LogConfigurationException {
...
for(int i=0; i<classesToDiscover.length && result == null; ++i) {
result = createLogFromClass(classesToDiscover[i], logCategory, true);
}
return result;
}
private Log createLogFromClass(String logAdapterClassName,String logCategory,boolean affectState){
Object[] params = { logCategory };
Log logAdapter = null;
Constructor constructor = null;
Class logAdapterClass = null;
ClassLoader currentCL = getBaseClassLoader();
for(;;) {
...
Class c = Class.forName(logAdapterClassName, true, currentCL);
constructor = c.getConstructor(logConstructorSignature);
Object o = constructor.newInstance(params);
if (o instanceof Log) {
logAdapterClass = c;
logAdapter = (Log) o;
break;
}
handleFlawedHierarchy(currentCL, c);
if (currentCL == null) {
break;
}
currentCL = getParentClassLoader(currentCL);
}
...
return logAdapter;
}
}
StaticLoggerBinder
是存在于各种日志适配桥接相关的依赖中,并且在不同依赖中该类的全限定名都为:org.slf4j.impl.StaticLoggerBinder。
例如,slf4j-jdk14是Slf4j对JUL适配的相关依赖,在其包中的类StaticLoggerBinder引入jul相关的日志核心类JDK14LoggerFactory。
public class JDK14LoggerFactory implements ILoggerFactory {
ConcurrentMap<String, Logger> loggerMap;
public JDK14LoggerFactory() {
java.util.logging.Logger.getLogger("");//获取JDK自带的日志框架实现
}
}
slf4j-log4j12是Slf4j对log4j适配的相关依赖,在其包中的类StaticLoggerBinder引入log4j相关的日志核心类Log4jLoggerFactory。
public class Log4jLoggerFactory implements ILoggerFactory {
ConcurrentMap<String, Logger> loggerMap;
public Log4jLoggerFactory() {
loggerMap = new ConcurrentHashMap<String, Logger>();
// force log4j to initialize
org.apache.log4j.LogManager.getRootLogger();//获取log4j自带的日志框架实现
}
}
public final class LoggerFactory {
private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
public static Logger getLogger(String name) {
ILoggerFactory iLoggerFactory = getILoggerFactory();
return iLoggerFactory.getLogger(name);
}
public static ILoggerFactory getILoggerFactory() {
if (INITIALIZATION_STATE == 0) {
synchronized (LoggerFactory.class) {
if (INITIALIZATION_STATE == 0) {
INITIALIZATION_STATE = 1;
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:
return SUBST_FACTORY;
}
throw new IllegalStateException("Unreachable code");
}
private final static void performInitialization() {
bind();
}
private final static void bind() {
Set<URL> staticLoggerBinderPathSet = null;
if (!isAndroid()) {
staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
}
// the next line does the binding
StaticLoggerBinder.getSingleton();
INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
reportActualBinding(staticLoggerBinderPathSet);
fixSubstituteLoggers();
replayEvents();
// release all resources in SUBST_FACTORY
SUBST_FACTORY.clear();
}
static Set<URL> findPossibleStaticLoggerBinderPathSet() {
Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>();
ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
Enumeration<URL> paths;
//利用StaticLoggerBinder引入具体的日志框架
if (loggerFactoryClassLoader == null) {
paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
} else {
paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
}
while (paths.hasMoreElements()) {
URL path = paths.nextElement();
staticLoggerBinderPathSet.add(path);
}
return staticLoggerBinderPathSet;
}
}
SpringBoot中是由包spring-boot-starter-logging提供的日志功能,该包下只是引入日志相关的门面技术以及具体的日志框架:logback-classic、log4j-to-slf4j、jul-to-slf4j。其中logback是完全实现了门面框架slf4j相关的API,所以可以与slf4j无缝衔接。但是log4j、jul其出现的时间都早于slf4j,所以其如果想利用门面技术slf4j时就需要相关的桥接技术,log4j-to-slf4j、jul-to-slf4j分别就是log4j、jul对应的桥接功能的实现者。