mybatis的Log机制浅谈
我们在使用Log时一般是这样定义Log的:Log log = LogFactory.getLog(class)。
mybatis也不例外,通过分析源码发现mybatis自己定义了Log和LogFactory,而没有采用我们通用的commons-logging或者slf4j-api。这样可以最少化对第三方日志框架的依赖性。
mybatis类之间的关系(工厂模式+状态模式)如下图所示:
从上图可以看出,它对不过是对org.slf4j、org.apache.commons.logging、org.apache.log4j、java.util.logging等六种Log框架的同时封装。
在加载LogFactory时,首先执行静态代码块,来决定使用何种日志框架。从代码中可以看到,采用日志框架是有先后顺序的。
static {
tryImplementation(new Runnable() {
public void run() {
useSlf4jLogging();
}
});
tryImplementation(new Runnable() {
public void run() {
useCommonsLogging();
}
});
tryImplementation(new Runnable() {
public void run() {
useLog4JLogging();
}
});
tryImplementation(new Runnable() {
public void run() {
useJdkLogging();
}
});
tryImplementation(new Runnable() {
public void run() {
useNoLogging();
}
});
}
private static void tryImplementation(Runnable runnable) {
if (logConstructor == null) {
try {
runnable.run(); // 不是启动新线程,而是普通的函数调用。
} catch (Throwable t) {
// ignore
}
}
}
public static synchronized void useSlf4jLogging() {
setImplementation("org.apache.ibatis.logging.slf4j.Slf4jImpl");
}
public static synchronized void useCommonsLogging() {
setImplementation("org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl");
}
public static synchronized void useLog4JLogging() {
setImplementation("org.apache.ibatis.logging.log4j.Log4jImpl");
}
public static synchronized void useJdkLogging() {
setImplementation("org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl");
}
public static synchronized void useStdOutLogging() {
setImplementation("org.apache.ibatis.logging.stdout.StdOutImpl");
}
public static synchronized void useNoLogging() {
setImplementation("org.apache.ibatis.logging.nologging.NoLoggingImpl");
}
决定采用何种框架是在setImplementation函数中。如果没有抛出异常,则采用此种框架。
private static void setImplementation(String implClassName) {
try {
@SuppressWarnings("unchecked")
Class<? extends Log> implClass = (Class<? extends Log>) Resources
.classForName(implClassName); // 查找实现类
Constructor<? extends Log> candidate = implClass
.getConstructor(new Class[] { Class.class });
Log log = candidate.newInstance(new Object[] { LogFactory.class });
log.debug("Logging initialized using '" + implClassName
+ "' adapter.");
logConstructor = candidate;
} catch (Throwable t) {
throw new LogException("Error setting Log implementation. Cause: "
+ t, t);
}
}