文件:
org.apache.ibatis.logging.LogFactory
日志加载顺序,初始化加载:
static {
tryImplementation(LogFactory::useSlf4jLogging);
tryImplementation(LogFactory::useCommonsLogging);
tryImplementation(LogFactory::useLog4J2Logging);
tryImplementation(LogFactory::useLog4JLogging);
tryImplementation(LogFactory::useJdkLogging);
tryImplementation(LogFactory::useNoLogging);
}
尝试加载任务:
private static void tryImplementation(Runnable runnable) {
// 这里只有当没有时,才尝试加载,加载到了就不尝试了
if (logConstructor == null) {
try {
runnable.run();
// 尝试加载,尝试失败时忽略异常
} catch (Throwable t) {
// ignore
}
}
}
日志类型加载任务内容:
public static synchronized void useLog4J2Logging() {
// Log4j2Impl类为mybatis对具体实现的包装类
// TODO Log4j2Impl这个封装类没有依赖的类,类不应该加载不出来吗,
// 我理解应该在这报错,但是进到方法里面了
setImplementation(org.apache.ibatis.logging.log4j2.Log4j2Impl.class);
}
日志类型加载任务具体实现:
private static void setImplementation(Class<? extends Log> implClass) {
try {
// 如果加载失败,直接throw,方法外面忽略Throwable
Constructor<? extends Log> candidate = implClass.getConstructor(String.class);
Log log = candidate.newInstance(LogFactory.class.getName());
// 如果加载成功,打出初始化日志
if (log.isDebugEnabled()) {
log.debug("Logging initialized using '" + implClass + "' adapter.");
}
// 保留加载成功的类型的构造器
logConstructor = candidate;
} catch (Throwable t) {
throw new LogException("Error setting Log implementation. Cause: " + t, t);
}
}
总结:
1.mybatis日志将每个加载任务的尝试动作抽象出来,抽象成任务,放在runnable中。将tryImplementation方法删去重写一遍这个类会有更深的理解。
2.LogFactory在静态代码块中初始化,尝试获取并持有log实现类的构造方法,getLog静态方法用持有的构造方法创建Log实体。
3.修改日志实现时,可在最开始时使org.apache.ibatis.logging.LogFactory.useSlf4jLogging();
修改日志实现。由于日志实例一般为静态的,所以需要在加载mybatis之前调用。调用时先执行LogFectory的静态代码块,顺序尝试加载日志实现,然后再去用自定义选择覆盖之前的持有。如果环境中并没有所选的相应实现,则直接抛异常。(官网这里说:“ For example, if you try to select Log4J logging and Log4J is not available at runtime, then MyBatis will ignore the request to use Log4J and will use it’s normal algorithm for discovering logging implementations.”貌似不太准确。)
问题:见代码中的 // TODO标记,额…