以 Executor 为例,分析MyBatis是如何为Executor实例植入插件逻辑的。Executor实例是在开启 SqlSession 时被创建的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// -☆- DefaultSqlSessionFactory
public SqlSession openSession() {
return openSessionFromDataSource(
configuration.getDefaultExecutorType(), null, false);
}

private SqlSession openSessionFromDataSource(ExecutorType execType,
TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
// 省略部分逻辑
// 创建 Executor
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
}
catch (Exception e) {...}
finally {...}
}

Executor 的创建过程封装在 Configuration 中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// -☆- Configuration
public Executor newExecutor(Transaction transaction,
ExecutorType executorType) {
executorType = executorType == null ?
defaultExecutorType : executorType;
executorType = executorType == null ?
ExecutorType.SIMPLE : executorType;
Executor executor;
// 根据 executorType 创建相应的 Executor 实例
if (ExecutorType.BATCH == executorType) {...}
else if (ExecutorType.REUSE == executorType) {...}
else {
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
// 植入插件
executor = (Executor) interceptorChain.pluginAll(executor);

return executor;
}

newExecutor 方法在创建好 Executor 实例后,紧接着通过拦截器链 interceptorChain
为 Executor 实例植入代理逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class InterceptorChain {
private final List<Interceptor> interceptors =
new ArrayList<Interceptor>();

public Object pluginAll(Object target) {
// 遍历拦截器集合
for (Interceptor interceptor : interceptors) {
// 调用拦截器的 plugin 方法植入相应的插件逻辑
target = interceptor.plugin(target);
}
return target;
}

/** 添加插件实例到 interceptors 集合中 */
public void addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
}

/** 获取插件列表 */
public List<Interceptor> getInterceptors() {
return Collections.unmodifiableList(interceptors);
}
}

它的 pluginAll 方法会调用具体插件的plugin方法植入相应的插件逻辑。如果有多个插件,则会多次调用 plugin 方法,最终生成一个层层嵌套的代理类。形如下面:

image.png
当 Executor 的某个方法被调用的时候,插件逻辑会先行执行。执行顺序由外而内

plugin 方法是由具体的插件类实现,不过该方法代码一般比较固定

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
// -☆- ExamplePlugin
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}

// -☆- Plugin
public static Object wrap(Object target, Interceptor interceptor) {
// 获取插件类 @Signature 注解内容,并生成相应的映射结构。形如下面
// {
// Executor.class : [query, update, commit],
// ParameterHandler.class : [getParameterObject, setParameters]
// }
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
Class<?> type = target.getClass();
// 获取目标类实现的接口
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
// 通过 JDK 动态代理为目标类生成代理类
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}

plugin 方法在内部调用了 Plugin 类的 wrap 方法,用于为目标对象生成代理。Plugin
类实现了InvocationHandler接口,因此它可以作为参数传给Proxy的newProxyInstance方法。