整体架构用了门面模式,对外暴露 SqlSession 接口
日志模块,采用了适配器模式
如果需要接入多个第三方 SDK 来满足自己的业务需求,但是 SDK 的接口定义与你的业务不兼容,又不能修改第三方 SDK 的代码,可以用适配器设计模式解决
MyBatis 定义了自己 Log 接口,为大部分主流日志框架都实现了 Adapter 适配器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public interface Log {
boolean isDebugEnabled();
boolean isTraceEnabled();
void error(String s, Throwable e);
void error(String s);
void debug(String s);
void trace(String s);
void warn(String s);
}
|
定义了四种 Log 级别,以 Slf4j 实现为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| public class Slf4jImpl implements Log {
private Log log;
public Slf4jImpl(String clazz) { Logger logger = LoggerFactory.getLogger(clazz);
if (logger instanceof LocationAwareLogger) { try { logger.getClass().getMethod("log", Marker.class, String.class, int.class, String.class, Object[].class, Throwable.class); log = new Slf4jLocationAwareLoggerImpl((LocationAwareLogger) logger); return; } catch (SecurityException | NoSuchMethodException e) { } }
log = new Slf4jLoggerImpl(logger); }
@Override public boolean isDebugEnabled() { return log.isDebugEnabled(); }
@Override public boolean isTraceEnabled() { return log.isTraceEnabled(); }
@Override public void error(String s, Throwable e) { log.error(s, e); }
@Override public void error(String s) { log.error(s); }
@Override public void debug(String s) { log.debug(s); }
@Override public void trace(String s) { log.trace(s); }
@Override public void warn(String s) { log.warn(s); }
}
|
同时定义了一个 LogFactory 类,日志的实例是从这里获取的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public final class LogFactory {
public static final String MARKER = "MYBATIS";
private static Constructor<? extends Log> logConstructor;
static { tryImplementation(LogFactory::useSlf4jLogging); tryImplementation(LogFactory::useCommonsLogging); tryImplementation(LogFactory::useLog4J2Logging); tryImplementation(LogFactory::useLog4JLogging); tryImplementation(LogFactory::useJdkLogging); tryImplementation(LogFactory::useNoLogging); }
private LogFactory() { } }
|
通过静态代码块定义了类加载的顺序,slf4j -> commons-logging -> log4j2 -> log4j -> jdk-logging -> no-logging
如果项目中有对应的依赖,则通过反射加载对应的日志接口
By the way,MyBatis 通过JDK 动态代理记录数据库连接,预编译语句,和结果记录,分别是 ConnectionLogger、PreparedStatementLogger 和 ResultSetLogger