- 注册 xml方式的注册,是在XMLConfigBuilder#pluginElement完成的。 不明觉厉的同学,请参考上一篇文章:Mybatis源码解读-配置加载和Mapper的生成
// XMLConfigBuilder#pluginElement(XNode parent)
private void pluginElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
// 读取插件的类路径
String interceptor = child.getStringAttribute("interceptor");
// 读取自定义参数
Properties properties = child.getChildrenAsProperties();
// 反射实例化插件
Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).getDeclaredConstructor().newInstance();
interceptorInstance.setProperties(properties);
// 将插件添加到配置的插件链中,等待后续使用
configuration.addInterceptor(interceptorInstance);
}
}
}
configuration.addInterceptor做得操作很简单
* 包装 上面讲了插件的注册,最后调用的是configuration.addInterceptor,最终调用的是InterceptorChain#addInterceptor
public class InterceptorChain {
private final List interceptors = new ArrayList<>();
/*
* 每当四大对象创建时,都会执行此方法
* 满足拦截条件,则返回Plugin代理,否则返回原对象
* @param target Mybatis四大对象之一
*/
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 getInterceptors() {
return Collections.unmodifiableList(interceptors);
}
}
我们案例是拦截StatementHandler,所以也以此为例
/*
* 这是创建StatementHandler的方法
* Configuration#newStatementHandler
*/
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之后,会调用InterceptorChain的pluginAll方法
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
那么我们再仔细分析下 pluginAll
方法, pluginAll
调用的是每个插件的 plugin
方法
default Object plugin(Object target) {
return Plugin.wrap(target, this);
}
可以看到,最终调用的是 Plugin.*wrap*
/*
* Plugin#wrap
* 判断是否满足插件的拦截条件,是则返回代理类,否则返回原对象
*/
public static Object wrap(Object target, Interceptor interceptor) {
// 获取插件的拦截信息(就是获取@Intercepts注解的内容)
Map, Set> signatureMap = getSignatureMap(interceptor);
Class type = target.getClass();
// 判断是否满足拦截条件
Class[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
// 满足拦截条件则返回Plugin代理对象
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
// 不满足则返回原对象
return target;
}
Original: https://www.cnblogs.com/konghuanxi/p/16273614.html
Author: 王谷雨
Title: Mybatis源码解读-插件
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/583270/
转载文章受原作者版权保护。转载请注明原作者出处!