Mybatis插件原理
如果对Mabatis运行流程不熟悉的,可以参考Mybatis执行流程,源码分析
pluginAll方法
在以下四大对象的创建过程中,出现了pluginAll方法
- Excutor
在Configuration的newExecutor方法中 - StatementHandler
在Configuration的newStatementHandler方法中 - ParameterHandler
在BaseStatementHandler的构造方法中 - ResultSetHandler
在BaseStatementHandler的构造方法中
其中, - ParameterHandler作为Statementhandler的成员,用以设置statement参数
- ResutSetHandler作为StatementHandler的成员,用以处理statement执行后的ResultSet
pluginAll方法代码也比较简单
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
看看Interceprtor拦截器接口
看到这里,应该很明确了,编写Mybatis的插件,也是通过代理实现的,Mybatis甚至为我们写好了代理类的创建过程
Plugin的wrap方法
public static Object wrap(Object target, Interceptor interceptor) {
/* 解析注解,获取拦截器需要拦截的方法 */
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
Class<?> type = target.getClass();
/* JDK动态代理,必须实现接口 */
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
/* 返回代理对象 */
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}
所以,我们得到的是一个Plugin对象,实现了invocationHandler接口,其中包含如下信息
Plugin类的invoke方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
Set<Method> methods = signatureMap.get(method.getDeclaringClass());
/* 我们的interceptor拦截目标方法,通过Invocation */
if (methods != null && methods.contains(method)) {
return interceptor.intercept(new Invocation(target, method, args));
}
return method.invoke(target, args);
} catch (Exception e) {
throw ExceptionUtil.unwrapThrowable(e);
}
}
再次感叹,动态代理真无处不在!
Q.E.D.