mybatis-基础支持层-日志模块
mybatis给出了一套统一的日志接口供上层对接不同形式的日志框架
一、特点:适配器模式
1.设计模式的六大原则
-
单一职责原则 : 一个类只负责唯一项职责
-
里式替换原则 : 遵循里式替换原则,能够设计出更为合适的继承体系
-
依赖倒置原则 : 系统的高层模块不应该依赖底层模块的实现,二者都应该依赖抽象类或接口
-
接口隔离原则 : 一个类对另一个类的依赖应该建立在最小的接口上
-
迪米特法则 : 一个对象应该对其他对象保持最少的了解
-
开放-封闭原则(最基础) :程序要对扩展开放,对修改关闭
2.适配器模式
主要用于解决接口不能兼容而导致的类无法使用的问题,适配器模式会将需要适配的类转换成调用者能够使用的目标接口 大量使用适配器,使得代码逻辑过于复杂并不建议
- 目标接口 Target :调用者能够直接使用的接口
- 需要适配的类 Adaptee :含有真正的业务逻辑,但是器接口不能被调用者直接使用
- 适配器 Adapter : 实现Target接口,并包装了一个Adaptee,在实现Target接口中的方法时,会将调用委托给Adaptee对象,Adaptee完成具体业务
class Adapter implement Target{
Adaptee adaptee;
void method(){
adaptee.method;
}
}
- 好处 复用现有组件,符合开放-封闭原则
3. case in Mybatis
- Target 接口
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);
}
- Adapter Adaptee
//其余case代码类似
public class Log4jImpl implements Log {
private static final String FQCN = Log4jImpl.class.getName();
//adaptee 负责实现业务逻辑
private final Logger log;
//在构造函数中,初始化adaptee
public Log4jImpl(String clazz) {
log = Logger.getLogger(clazz);
}
@Override
public boolean isDebugEnabled() {
return log.isDebugEnabled();
}
@Override
public boolean isTraceEnabled() {
return log.isTraceEnabled();
}
@Override
public void error(String s, Throwable e) {
log.log(FQCN, Level.ERROR, s, e);
}
@Override
public void error(String s) {
log.log(FQCN, Level.ERROR, s, null);
}
@Override
public void debug(String s) {
log.log(FQCN, Level.DEBUG, s, null);
}
@Override
public void trace(String s) {
log.log(FQCN, Level.TRACE, s, null);
}
@Override
public void warn(String s) {
log.log(FQCN, Level.WARN, s, null);
}
}
二、LogFactory
LogFactory 用于初始化使用的日志框架Adapter
- mybatis整合了多种日志框架,提供trace/debug/warn/errpr四个级别
class LogFactory{
....
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 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.class);
}
private static void setImplementation(Class<? extends Log> implClass) {
try {
//获取构造方法
Constructor<? extends Log> candidate = implClass.getConstructor(String.class);
//newInstance 初始化
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. 代理模式
- Subject 业务逻辑接口
- RealSubject 实现接口逻辑的真正业务类
-
Proxy : 实现Subject的代理类,内含Subject realSubject对象,程序中不会直接调用RealSubject, Proxy中的接口实现中采用RealSubject的实现,但是Proxy会在前面进行前置处理,后面进行后置处理
- 目的是:实现对RealSubject的访问控制,并在业务执行前后进行前置处理和后置处理,还可以实现延迟加载功能。mybatis中使用延迟初始化数据库连接进行查询,得到一个代理对象,没有执行任何查询的时候并没有真正获取连接,如果真正需要查询再调用代理方法进行数据库查询,很好地减少了消耗
-
代理对象可以协调真正的RealSubject与调用者之间的关系
- 代理模式分为:静态代理,动态代理,上面描述的是静态代理模式,当需要大量的代理的时候,会出现大量的代理类
- 动态代理分为:基于接口的jdk动态代理,基于继承的CGLIB动态代理,这里主要面向接口方法,主要了解一下JDK动态代理
2. JDK动态代理
- 入口: Proxy.newProxyInstance
- 1.检验类的安全合理
- 2.尝试从缓存获取类
- 3.缓存中不存在,调用ProxyClassFactory apply
- 4.检测interface集合的合法性
- 5.根据包名、代理类前缀、编号生成代理类名称
- 6.编译获取class,写入文件,缓存class对象
- 7.加载代理类,返回class对象
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
//检查类是否安全
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
* 获取代理类
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
//获取代理类的构造方法
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
//创建代理类
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
/**
* a cache of proxy classes
* 代理类缓存
* 首先尝试从缓存中查找代理类,如果查找不到,会创建Factory 对象并调用其get方法获取代理类
* Factory使其内部类
*/
private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
//代理类缓存
return proxyClassCache.get(loader, interfaces);
}
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
//实现代理类加载的部分
//1. 检查interfaces集合
//2. 选择定义代理类的包名
//3.代理的名称是通过包名、代理类名称前缀以及编号组成
/*
* Choose a name for the proxy class to generate.
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
//加载代理类,返回class对象
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
}
}
class ProxyGenerator{
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
//初始化class内容
final byte[] var4 = var3.generateClassFile();
if (saveGeneratedFiles) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
try {
int var1 = var0.lastIndexOf(46);
Path var2;
if (var1 > 0) {
//写入文件
Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
Files.createDirectories(var3);
var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
} else {
var2 = Paths.get(var0 + ".class");
}
Files.write(var2, var4, new OpenOption[0]);
return null;
} catch (IOException var4x) {
throw new InternalError("I/O exception saving generated file: " + var4x);
}
}
});
}
return var4;
}
}
class WeakCache{
public V get(K key, P parameter) {
Objects.requireNonNull(parameter);
expungeStaleEntries();
//构建CacheKey对象 new CacheKey<>(key, refQueue)
Object cacheKey = CacheKey.valueOf(key, refQueue);
// lazily install the 2nd level valuesMap for the particular cacheKey
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
// create subKey and retrieve the possible Supplier<V> stored by that
// subKey from valuesMap
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier<V> supplier = valuesMap.get(subKey);
//内部类Factory
Factory factory = null;
while (true) {
if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
V value = supplier.get();
if (value != null) {
return value;
}
}
// else no supplier in cache
// or a supplier that returned null (could be a cleared CacheValue
// or a Factory that wasn't successful in installing the CacheValue)
// lazily construct a Factory
if (factory == null) {
//构建Factory
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
// successfully replaced
// cleared CacheEntry / unsuccessful Factory
// with our Factory
supplier = factory;
} else {
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}
....
//内部类,实现Supplier ,绑定key subKey
//A factory {@link Supplier} that implements the **lazy synchronized**
private final class Factory implements Supplier<V> {
private final K key;
private final P parameter;
private final Object subKey;
private final ConcurrentMap<Object, Supplier<V>> valuesMap;
...
//new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
public WeakCache(BiFunction<K, P, ?> subKeyFactory,
BiFunction<K, P, V> valueFactory) {
this.subKeyFactory = Objects.requireNonNull(subKeyFactory);//new KeyFactory()
this.valueFactory = Objects.requireNonNull(valueFactory);// new ProxyClassFactory()
}
@Override
public synchronized V get() { // serialize access
// re-check
Supplier<V> supplier = valuesMap.get(subKey);
if (supplier != this) {
// something changed while we were waiting:
// might be that we were replaced by a CacheValue
// or were removed because of failure ->
// return null to signal WeakCache.get() to retry
// the loop
return null;
}
// else still us (supplier == this)
// create new value
V value = null;
try {
value = Objects.requireNonNull(valueFactory.apply(key, parameter));
} finally {
if (value == null) { // remove us on failure
valuesMap.remove(subKey, this);
}
}
// the only path to reach here is with non-null value
assert value != null;
// wrap value with CacheValue (WeakReference)
CacheValue<V> cacheValue = new CacheValue<>(value);
// put into reverseMap
reverseMap.put(cacheValue, Boolean.TRUE);
// try replacing us with CacheValue (this should always succeed)
if (!valuesMap.replace(subKey, this, cacheValue)) {
throw new AssertionError("Should not reach here");
}
// successfully replaced us with new CacheValue -> return the value
// wrapped by it
return value;
}
}
}
四、JDBC日志
与我们日常的使用也十分接近,我们通常希望打印sql语句,有时候show-sql=true就能够实现,就是因为底层框架做了这方面的实现,今天来看一下如何实现打印SQL、用户传入绑定参数、结果日志等
BaseJdbcLogger
|
|
|----------------------|-----------------------|---------------------|
ConnectionLogger PreparedStatementLogger ResultSetLogger StatementLogger
上面的命名就能够清晰地看得出,每一个Logger主要面向哪一部分的功能
BaseJdbcLogger : 定义了SET_METHODS / EXECUTE_METHODS 的集合
ConnectionLogger: 封装了Connention对象,同时实现了InvocationHandler
1. BaseJdbcLogger
- 属性
//set方法
protected static final Set<String> SET_METHODS;
//执行方法
protected static final Set<String> EXECUTE_METHODS = new HashSet<>();
//记录了PreparedStatement.set* 方法设置的键值对
private final Map<Object, Object> columnMap = new HashMap<>();
//记录了PreparedStatement.set* 方法的keys
private final List<Object> columnNames = new ArrayList<>();
//记录了PreparedStatement.set* 方法的values
private final List<Object> columnValues = new ArrayList<>();
//log对象
protected final Log statementLog;
//SQL层数,用于格式化输出SQL
protected final int queryStack;
2.ConnectionLogger
- 封装了Connention对象,同时实现了InvocationHandler,通过newInstance获取Connention对象,通过Invoke方法实现方法的执行
private final Connection connection;
private ConnectionLogger(Connection conn, Log statementLog, int queryStack) {
super(statementLog, queryStack);
this.connection = conn;
}
public static Connection newInstance(Connection conn, Log statementLog, int queryStack) {
InvocationHandler handler = new ConnectionLogger(conn, statementLog, queryStack);
ClassLoader cl = Connection.class.getClassLoader();
return (Connection) Proxy.newProxyInstance(cl, new Class[]{Connection.class}, handler);
}
@Override
public Object invoke(Object proxy, Method method, Object[] params)
throws Throwable {
try {
//Object方法,直接调用
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, params);
}
//如果调用prepareStatement、prepareCall、createStatement方法,需要创建对象
if ("prepareStatement".equals(method.getName()) || "prepareCall".equals(method.getName())) {
if (isDebugEnabled()) {
debug(" Preparing: " + removeExtraWhitespace((String) params[0]), true);
}
//调用底层Connetion 对象的PreparedStatement方法创建 PreparedStatement对象
PreparedStatement stmt = (PreparedStatement) method.invoke(connection, params);
//获取PreparedStatement的代理类
stmt = PreparedStatementLogger.newInstance(stmt, statementLog, queryStack);
return stmt;
} else if ("createStatement".equals(method.getName())) {
Statement stmt = (Statement) method.invoke(connection, params);
stmt = StatementLogger.newInstance(stmt, statementLog, queryStack);
return stmt;
} else {
//其他直接调用Connection的相应方法
return method.invoke(connection, params);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
3.PreparedStatementLogger
//内部PreparedStatement对象,也有newInstance获取PreparedStatement
private final PreparedStatement statement;
//invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, params);
}
//调用了EXECTE的方法
if (EXECUTE_METHODS.contains(method.getName())) {
if (isDebugEnabled()) {
debug("Parameters: " + getParameterValueString(), true);
}
//清空BaseJdbcLogger中的三个column缓存
clearColumnInfo();
if ("executeQuery".equals(method.getName())) {
//为返回结果创建代理类
ResultSet rs = (ResultSet) method.invoke(statement, params);
//ResultSetLogger.newInstance
return rs == null ? null : ResultSetLogger.newInstance(rs, statementLog, queryStack);
} else {
return method.invoke(statement, params);
}
} else if (SET_METHODS.contains(method.getName())) {
//如果是调用了SET的方法,通过setColumn记录到BaseJdbcLogger的set column记录中
if ("setNull".equals(method.getName())) {
setColumn(params[0], null);
} else {
setColumn(params[0], params[1]);
}
return method.invoke(statement, params);
} else if ("getResultSet".equals(method.getName())) {
//如果是获取结果集,则创建 ResultSet代理类,ResultSetLogger.newInstance
ResultSet rs = (ResultSet) method.invoke(statement, params);
return rs == null ? null : ResultSetLogger.newInstance(rs, statementLog, queryStack);
} else if ("getUpdateCount".equals(method.getName())) {
int updateCount = (Integer) method.invoke(statement, params);
if (updateCount != -1) {
debug(" Updates: " + updateCount, false);
}
return updateCount;
} else {
return method.invoke(statement, params);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
4.ResultSetLogger
- 内部也有ResultSet对象,也有newInstance方法获取ResultSet对象,
public final class ResultSetLogger extends BaseJdbcLogger implements InvocationHandler {
//超长字段的类型
private static final Set<Integer> BLOB_TYPES = new HashSet<>();
//是否是ResultSet的结果集第一行
private boolean first = true;
//行数
private int rows;
//结果集
private final ResultSet rs;
//超大字段的列编号
private final Set<Integer> blobColumns = new HashSet<>();
@Override
public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {
try {
//Object方法直接调用
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, params);
}
Object o = method.invoke(rs, params);
//调用结果集的next方法进行遍历
if ("next".equals(method.getName())) {
if ((Boolean) o) { //是否存在下一行数据
rows++;
if (isTraceEnabled()) {
ResultSetMetaData rsmd = rs.getMetaData();
//获取数据集的列数
final int columnCount = rsmd.getColumnCount();
if (first) {
//第一行
first = false;
//打印列名,包括超长字段
printColumnHeaders(rsmd, columnCount);
}
//打印累的内容 ,打印的时候不包含超长字段
printColumnValues(columnCount);
}
} else {
debug(" Total: " + rows, false);
}
}
//清空BaseJdbcLogger中的column集合
clearColumnInfo();
return o;
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
}