核心功能拆解 Plugin插件功能实现
Mybatis Plugin 是随着 Mybatis 的工作流程一起被进行 解析->注册->执行
的,了解每个步骤才能更好的对 Mybatis 所提供的 Plugin 机制进行实现和扩展。在我们已知的 Mybatis 的插件有分页插件、缓存插件等,之所以可以能做到扩展是因为他在自己本身的 Executor(生产执行器)
, StatementHandler(语句处理器)
, ParameterHandler(参数处理器)
, ResultSetHandler(结果集处理器)
这四个地方做了拦截,当介绍到执行步骤的时候就可以看到具体实现。
# 解析
常规的 XML 配置
<plugins>
<plugin interceptor="cn.mybatis.test.plugin.TestPlugin">
<property name="test00" value="100"/>
<property name="test01" value="200"/>
</plugin>
</plugins>
2
3
4
5
6
核心解析方法
private void pluginElement(Element parent) throws Exception {
if (parent == null) return;
List<Element> elements = parent.elements();
for (Element element : elements) {
// 解析类路径
String interceptor = element.attributeValue("interceptor");
// 参数配置
Properties properties = new Properties();
List<Element> propertyElementList = element.elements("property");
for (Element property : propertyElementList) {
properties.setProperty(property.attributeValue("name"), property.attributeValue("value"));
}
// 获取插件实现类并实例化:cn.mybatis.test.plugin.TestPlugin
// 通过 Resources.classForName(string) 获取实例
Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
// 设置配置属性
interceptorInstance.setProperties(properties);
// 注册到 configuration 中
configuration.addInterceptor(interceptorInstance);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 注册
解析的时候会在方法内部执行 configuration.addInterceptor(interceptorInstance);
这一步是把插件维护到 Configuration
全局配置中,但插件其实应该有很多各,所以提供的是一个 InterceptorChain
对象由 Configuration
维护
public class Configuration {
// 插件拦截器链
protected final InterceptorChain interceptorChain = new InterceptorChain();
public void addInterceptor(Interceptor interceptorInstance) {
interceptorChain.addInterceptor(interceptorInstance);
}
// other 其他配置
}
2
3
4
5
6
7
8
InterceptorChain
里面维护的是一个集合,专门存放所有的 Plugin
public class InterceptorChain {
// 插件拦截器容器
private final List<Interceptor> interceptors = new ArrayList<>();
//
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
// 添加到插件容器
public void addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
}
public List<Interceptor> getInterceptors(){
return Collections.unmodifiableList(interceptors);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
从解析到注册这两步就可以看出,MyBatis 是把插件以拦截器的形式存放到一个拦截器容器里,这个容器是 Configuration
全局配置类来进行维护的
# 执行
执行是在调用具体的查询方法活其他在 Mybatis 里所描述的 SQL 方法时进行的触发,触发会在如下代码中的位置中触发。
// 创建参数处理器
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
return parameterHandler;
}
// 创建结果集处理器
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
ResultHandler resultHandler, BoundSql boundSql) {
ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
return resultSetHandler;
}
// 创建语句处理器
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
// 生产执行器
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
// 批量处理器
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
// 简单处理器
executor = new SimpleExecutor(this, transaction);
}
// 二级缓存处理器
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
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
会看到他会调用 InterceptorChain#pluginAll
方法,该类在注册步骤中有提及到,里面维护了所有的插件,那么在这里就会时循环所有的插件,每个插件调用 Interceptor#plugin
// 循环调用
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
// 执行wrap
public interface Interceptor {
// 拦截,使用方实现
Object intercept(Invocation invocation) throws Throwable;
// 代理
default Object plugin(Object target) {
return Plugin.wrap(target, this);
}
// 设置属性
default void setProperties(Properties properties) {
// NOP
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Interceptor#plugin
方法内部也就是调用 Plugin#wrap
静态方法,该方法通过获取自定义插件的注解,来观察你需要对哪个处理器,哪个方法以及参数类型去匹配拦截对象的具体方法,如果多一个参数都可能找不到要拦截的方法。找到方法后然后去动态代理这个方法。
//
public class Plugin implements InvocationHandler {
private Object target;
private Interceptor interceptor;
private Map<Class<?>, Set<Method>> signatureMap;
private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) {
this.target = target;
this.interceptor = interceptor;
this.signatureMap = signatureMap;
}
// 具体的代理实现
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 获取声明的方法列表
Set<Method> methods = signatureMap.get(method.getDeclaringClass());
// 过滤需要拦截的方法
if (methods != null && methods.contains(method)) {
// 调用 Interceptor#intercept 插入自己的反射逻辑
return interceptor.intercept(new Invocation(target, method, args));
}
return method.invoke(target, args);
}
/**
* 用代理把自定义插件行为包裹到目标方法中,也就是 Plugin.invoke 的过滤调用
*/
public static Object wrap(Object target, Interceptor interceptor) {
// 取得签名Map
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
// 取得要改变行为的类(ParameterHandler|ResultSetHandler|StatementHandler|Executor)
Class<?> type = target.getClass();
// 取得接口
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
// 创建代理(StatementHandler)
if (interfaces.length > 0) {
// 代理
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}
/**
* 获取方法签名组 Map
*/
private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
// 取 Intercepts 注解
Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
// 必须得有 Intercepts 注解,没有报错
if (interceptsAnnotation == null) {
throw new RuntimeException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());
}
// value是数组型,Signature的数组
Signature[] sigs = interceptsAnnotation.value();
// 每个 class 类有多个可能有多个 Method 需要被拦截
Map<Class<?>, Set<Method>> signatureMap = new HashMap<>();
for (Signature sig : sigs) {
Set<Method> methods = signatureMap.computeIfAbsent(sig.type(), k -> new HashSet<>());
try {
// 例如获取到方法;StatementHandler.prepare(Connection connection)、StatementHandler.parameterize(Statement statement)...
Method method = sig.type().getMethod(sig.method(), sig.args());
methods.add(method);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e);
}
}
return signatureMap;
}
/**
* 取得接口
*/
private static Class<?>[] getAllInterfaces(Class<?> type, Map<Class<?>, Set<Method>> signatureMap) {
Set<Class<?>> interfaces = new HashSet<Class<?>>();
while (type != null) {
for (Class<?> c : type.getInterfaces()) {
// 拦截 ParameterHandler|ResultSetHandler|StatementHandler|Executor
if (signatureMap.containsKey(c)) {
interfaces.add(c);
}
}
type = type.getSuperclass();
}
return interfaces.toArray(new Class<?>[interfaces.size()]);
}
}
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# 自定义
package cn.mybatis.test.plugin;
import cn.mybatis.executor.statement.StatementHandler;
import cn.mybatis.mapping.BoundSql;
import cn..mybatis.plugin.Interceptor;
import cn.mybatis.plugin.Intercepts;
import cn.mybatis.plugin.Invocation;
import cn.mybatis.plugin.Signature;
import java.sql.Connection;
import java.util.Properties;
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class})})
public class TestPlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 获取StatementHandler
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
// 获取SQL信息
BoundSql boundSql = statementHandler.getBoundSql();
String sql = boundSql.getSql();
// 输出SQL
System.out.println("拦截SQL:" + sql);
// 放行
return invocation.proceed();
}
@Override
public void setProperties(Properties properties) {
System.out.println("参数输出:" + properties.getProperty("test00"));
}
}
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