今天再看spring-jcl模块里的源码,这个模块是spring源码里最基础的模块没有依赖其他模块,它是为了兼容不同版本的日志系统。一看居然还有这种写法,看得我一愣一愣的,三层try嵌套,利用异常去做业务控制。采用适配器模式,和工厂模式
在虚拟机启动的时候确定项目用的是哪一种日志实现兼容
// LogAdapter
static {
ClassLoader cl = LogAdapter.class.getClassLoader();
try {
// Try Log4j 2.x API
Class.forName("org.apache.logging.log4j.spi.ExtendedLogger", false, cl);
logApi = LogApi.LOG4J;
}
catch (ClassNotFoundException ex1) {
try {
// Try SLF4J 1.7 SPI
Class.forName("org.slf4j.spi.LocationAwareLogger", false, cl);
logApi = LogApi.SLF4J_LAL;
}
catch (ClassNotFoundException ex2) {
try {
// Try SLF4J 1.7 API
Class.forName("org.slf4j.Logger", false, cl);
logApi = LogApi.SLF4J;
}
catch (ClassNotFoundException ex3) {
// 使用默认的 java.util.logging
// Keep java.util.logging as default
}
}
}
}
根据确定的日志系统,创建日志对象
// LogAdapter
/** 选中的API创建真实的log对象
* Create an actual {@link Log} instance for the selected API.
* @param name the logger name
*/
public static Log createLog(String name) {
switch (logApi) {
case LOG4J:
return Log4jAdapter.createLog(name);
case SLF4J_LAL:
return Slf4jAdapter.createLocationAwareLog(name);
case SLF4J:
return Slf4jAdapter.createLog(name);
default:
// Defensively use lazy-initializing adapter class here as well since the
// java.logging module is not present by default on JDK 9. We are requiring
// its presence if neither Log4j nor SLF4J is available; however, in the
// case of Log4j or SLF4J, we are trying to prevent early initialization
// of the JavaUtilLog adapter - e.g. by a JVM in debug mode - when eagerly
// trying to parse the bytecode for all the cases of this switch clause.
return JavaUtilAdapter.createLog(name);
}
}
采用工厂模式去新建log对象
public abstract class LogFactory {
/**
* Convenience method to return a named logger.
* @param clazz containing Class from which a log name will be derived
*/
public static Log getLog(Class<?> clazz) {
return getLog(clazz.getName());
}
/**
* Convenience method to return a named logger.
* @param name logical name of the <code>Log</code> instance to be returned
*/
public static Log getLog(String name) {
return LogAdapter.createLog(name);
}
/**
* This method only exists for compatibility with unusual Commons Logging API
* usage like e.g. {@code LogFactory.getFactory().getInstance(Class/String)}.
* @see #getInstance(Class)
* @see #getInstance(String)
* @deprecated in favor of {@link #getLog(Class)}/{@link #getLog(String)}
*/
@Deprecated
public static LogFactory getFactory() {
return new LogFactory() {};
}
/**
* Convenience method to return a named logger.
* <p>This variant just dispatches straight to {@link #getLog(Class)}.
* @param clazz containing Class from which a log name will be derived
* @deprecated in favor of {@link #getLog(Class)}
*/
@Deprecated
public Log getInstance(Class<?> clazz) {
return getLog(clazz);
}
/**
* Convenience method to return a named logger.
* <p>This variant just dispatches straight to {@link #getLog(String)}.
* @param name logical name of the <code>Log</code> instance to be returned
* @deprecated in favor of {@link #getLog(String)}
*/
@Deprecated
public Log getInstance(String name) {
return getLog(name);
}
}