首先日志模块采用的是适配器模式:因为日志厂商,没有专门针对Mybatis的专门日志模块。所以Mybatis要引入外部的日志模块,于是才用了该设计模式
2.日志模块所在位置
org.apache.ibatis.logging
例:
//jdkLog的适配器,实现的是Log接口(Mybatie自己规定的日志需要有的能力) public class Jdk14LoggingImpl implements Log { //真正提供日志能力的jdk的日志类(这就是引入的外部实现类) private final Logger log; public Jdk14LoggingImpl(String clazz) { log = Logger.getLogger(clazz); } @Override public boolean isDebugEnabled() { return log.isLoggable(Level.FINE); } @Override public boolean isTraceEnabled() { return log.isLoggable(Level.FINER); } @Override public void error(String s, Throwable e) { log.log(Level.SEVERE, s, e); } @Override public void error(String s) { log.log(Level.SEVERE, s); } @Override public void debug(String s) { log.log(Level.FINE, s); } @Override public void trace(String s) { log.log(Level.FINER, s); } @Override public void warn(String s) { log.log(Level.WARNING, s); } }
3.Mybatis又是怎样加载到Mybatis框架里面的
下面我们看看 LogFactory 这个类,这里通过静态代码块,实现了日志框架的加载顺序
public final class LogFactory { /** * Marker to be used by logging implementations that support markers */ public static final String MARKER = "MYBATIS"; //被选定的第三方日志组件适配器的构造方法 private static Constructor<? extends Log> logConstructor; //自动扫描日志实现,并且第三方日志插件加载优先级如下:slf4J → commonsLoging → Log4J2 → Log4J → JdkLog static { tryImplementation(LogFactory::useSlf4jLogging); tryImplementation(LogFactory::useCommonsLogging); tryImplementation(LogFactory::useLog4J2Logging); tryImplementation(LogFactory::useLog4JLogging); tryImplementation(LogFactory::useJdkLogging); tryImplementation(LogFactory::useNoLogging); } private LogFactory() { // disable construction } public static Log getLog(Class<?> aClass) { return getLog(aClass.getName()); } public static Log getLog(String logger) { try { return logConstructor.newInstance(logger); } catch (Throwable t) { throw new LogException("Error creating logger for logger " + logger + ". Cause: " + t, t); } } public static synchronized void useCustomLogging(Class<? extends Log> clazz) { setImplementation(clazz); } public static synchronized void useSlf4jLogging() { setImplementation(org.apache.ibatis.logging.slf4j.Slf4jImpl.class); } public static synchronized void useCommonsLogging() { setImplementation(org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl.class); } public static synchronized void useLog4JLogging() { setImplementation(org.apache.ibatis.logging.log4j.Log4jImpl.class); } public static synchronized void useLog4J2Logging() { setImplementation(org.apache.ibatis.logging.log4j2.Log4j2Impl.class); } public static synchronized void useJdkLogging() { setImplementation(org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl.class); } public static synchronized void useStdOutLogging() { setImplementation(org.apache.ibatis.logging.stdout.StdOutImpl.class); } public static synchronized void useNoLogging() { setImplementation(org.apache.ibatis.logging.nologging.NoLoggingImpl.class); } private static void tryImplementation(Runnable runnable) { if (logConstructor == null) {//当构造方法不为空才执行方法 try { runnable.run(); } catch (Throwable t) { // ignore } } } //通过指定的log类来初始化构造方法 private static void setImplementation(Class<? extends Log> implClass) { try { 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); } } }