1.JCL
public abstract class LogFactory {public static Log getLog(Class clazz) throws LogConfigurationException {// 默认实现类为LogFactoryImplreturn 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;}
}
2.Slf4j
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 initializeorg.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 bindingStaticLoggerBinder.getSingleton();INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;reportActualBinding(staticLoggerBinderPathSet);fixSubstituteLoggers();replayEvents();// release all resources in SUBST_FACTORYSUBST_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;}
}
3.SpringBoot默认日志类型
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对应的桥接功能的实现者。