1.XMLConfigBuilder中解析plugins
XMLConfigBuilder的parseConfiguration中,通过XPath解析Document的plugins节点得到XNode对象,然后调用pluginElement方法进行处理
private void parseConfiguration(XNode root) {
...
this.pluginElement(root.evalNode("plugins"));
...
}
pluginElement方法中,获取plugins的所有子配置,然后依次进行处理
获取插件的配置interceptor和属性,然后通过反射的方式进行实例化,然后强转为Interceptor类型,并使用Properties对Interceptor属性进行赋值,最后添加到Configuration中
private void pluginElement(XNode parent) throws Exception {
if (parent != null) {
Iterator var2 = parent.getChildren().iterator();
while(var2.hasNext()) {
XNode child = (XNode)var2.next();
String interceptor = child.getStringAttribute("interceptor");
Properties properties = child.getChildrenAsProperties();
Interceptor interceptorInstance = (Interceptor)this.resolveClass(interceptor).getDeclaredConstructor().newInstance();
interceptorInstance.setProperties(properties);
this.configuration.addInterceptor(interceptorInstance);
}
}
}
resolveClass方法是通过别名字符串获取到Configuration中的typeAliasRegistry获取对应的类对象,得到后即可通过反射获取构造方法来进行实例化
protected <T> Class<? extends T> resolveClass(String alias) {
if (alias == null) {
return null;
} else {
try {
return this.resolveAlias(alias);
} catch (Exception var3) {
throw new BuilderException("Error resolving class. Cause: " + var3, var3);
}
}
}
2.Interceptor接口
由上述过程可以知道,配置的Plugins - interceptor在创建对象后,会强制转型为Interceptor类型,Interceptor是一个接口,包括以下三个方法
通过setProperties方法将配置的属性进行赋值
public interface Interceptor {
Object intercept(Invocation var1) throws Throwable;
default Object plugin(Object target) {
return Plugin.wrap(target, this);
}
default void setProperties(Properties properties) {
}
}
3.添加到Configuration
最后通过addInterceptor将创建的Interceptor添加到interceptorChain中,interceptorChain是InterceptorChain类型的实例
public class Configuration {
protected final InterceptorChain interceptorChain;
public Configuration() {
...
this.interceptorChain = new InterceptorChain();
...
}
public void addInterceptor(Interceptor interceptor) {
this.interceptorChain.addInterceptor(interceptor);
}
...
}
4.InterceptorChain类
InterceptorChain中有一个Interceptor的集合对象,
public class InterceptorChain {
private final List<Interceptor> interceptors = new ArrayList();
public void addInterceptor(Interceptor interceptor) {
this.interceptors.add(interceptor);
}
...
}
5.Interceptor执行流程
InterceptorChain在pluginAll方法中会依次调用Interceptor的plugin方法对传入的参数进行处理
public Object pluginAll(Object target) {
Interceptor interceptor;
for(Iterator var2 = this.interceptors.iterator(); var2.hasNext(); target = interceptor.plugin(target)) {
interceptor = (Interceptor)var2.next();
}
return target;
}
Interceptor中的plugin方法通过Plugin的warp来执行,传入参数target和Interceptor的引用
default Object plugin(Object target) {
return Plugin.wrap(target, this);
}
Plugin实现了Java动态代理接口InvocationHandler,在wrap方法中通过动态代理方式创建对象,代理对象就是其自身的实例
最后在方法执行时,会先判断signatureMap有没有该方法,有的话就调用interceptor中的intercept方法,否则正常执行方法即可
public class Plugin implements InvocationHandler {
private final Object target;
private final Interceptor interceptor;
private final 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;
}
public static Object wrap(Object target, Interceptor interceptor) {
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
Class<?> type = target.getClass();
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
return interfaces.length > 0 ? Proxy.newProxyInstance(type.getClassLoader(), interfaces, new Plugin(target, interceptor, signatureMap)) : target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
Set<Method> methods = (Set)this.signatureMap.get(method.getDeclaringClass());
return methods != null && methods.contains(method) ? this.interceptor.intercept(new Invocation(this.target, method, args)) : method.invoke(this.target, args);
} catch (Exception var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
}
}
getSignatureMap方法中对Interceptor的注解进行解析为signatureMap
private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
Intercepts interceptsAnnotation = (Intercepts)interceptor.getClass().getAnnotation(Intercepts.class);
if (interceptsAnnotation == null) {
throw new PluginException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());
} else {
Signature[] sigs = interceptsAnnotation.value();
Map<Class<?>, Set<Method>> signatureMap = new HashMap();
Signature[] var4 = sigs;
int var5 = sigs.length;
for(int var6 = 0; var6 < var5; ++var6) {
Signature sig = var4[var6];
Set methods = (Set)signatureMap.computeIfAbsent(sig.type(), (k) -> {
return new HashSet();
});
try {
Method method = sig.type().getMethod(sig.method(), sig.args());
methods.add(method);
} catch (NoSuchMethodException var10) {
throw new PluginException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + var10, var10);
}
}
return signatureMap;
}
}
6.拦截器的执行
查看Configuration中的代码,一下四处代码中调用InterceptorChain的pluginAll方法,也就是说插件暂时只支持处理Executor,ParameterHandler,ResultSetHandler,StatementHandler四个参数
7.总结
Mybatis插件是通过拦截器来实现的,自定义插件时,可以配置对Mybatis四种类型的的方法进行拦截,然后在对象执行拦截方法时,对调用Interceptor的intercept方法,我们可以通过自定义拦截器重写intercept方法来实现对应的业务逻辑,而拦截器则是通过Java动态代理实现
后续对于Mybatis插件的开发,先要熟悉Executor,ParameterHandler,ResultSetHandler,StatementHandler四个组件的方法的作用与调用时机,才可对具体方法添加拦截器以实现附加功能