org.apache.ibatis.plugin.InterceptorChain
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);
}
}
ParameterHandler
, ResultSetHandler
, StatementHandler
, Executor
对象时调用pluginAll(Object target)
方法,遍历Interceptor
执行org.apache.ibatis.plugin.Interceptor#plugin
,org.apache.ibatis.plugin.Plugin#wrap(Object target, Interceptor interceptor)
解析Interceptor
上定义的@Intercepts
和@Signature
注解来解析需要被拦截的方法,对其使用JDK动态代理,代理类的java.lang.reflect.InvocationHandler
实现即为org.apache.ibatis.plugin.Plugin
,target
做为Plugin的成员变量保存。interceptor
,需要则执行。不需要则直接调用target目标类的方法。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);
if (interfaces.length > 0) {
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
Set<Method> methods = signatureMap.get(method.getDeclaringClass());
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);
}
}
......
}
在循环调用interceptor.plugin(target);
时, 如果存在多个Interceptor
拦截的即使是同一个接口(ParameterHandler
, ResultSetHandler
, StatementHandler
, Executor
其中一个),因为每次传入的是上一个target = interceptor.plugin(target)
返回的对象,会导致目标类被代理多次。这实际上形成了一个动态代理的拦截器链
ProxyA(Hnadler)
--> ProxyB(Hnadler)
--> ProxyC(Hnadler)
--> ProxyD(Hnadler)
......
org.apache.ibatis.plugin.Plugin
package org.apache.ibatis.plugin;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.ibatis.reflection.ExceptionUtil;
/**
* @author bruce lwl
*/
public class Plugin implements InvocationHandler {
private final Object target;
//private final Interceptor interceptor;
//private final Map, Set> signatureMap;
private final Map<Method, List<Interceptor>> interceptorMap;
//private Plugin(Object target, Interceptor interceptor, Map, Set> signatureMap) {
private Plugin(Object target, Interceptor interceptor, Map<Method, List<Interceptor>> interceptorMap) {
this.target = target;
//this.interceptor = interceptor;
//this.signatureMap = signatureMap;
this.interceptorMap = interceptorMap;
}
public Map<Method, List<Interceptor>> getInterceptorMap() {
return interceptorMap;
}
public static Object wrap(Object target, Interceptor interceptor) {
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
Class<?> type = target.getClass();
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
if (Proxy.isProxyClass(target.getClass())) {
InvocationHandler invocationHandler = Proxy.getInvocationHandler(target);
if (invocationHandler instanceof Plugin){
Map<Method, List<Interceptor>> interceptorMap = ((Plugin) invocationHandler).getInterceptorMap();
mapping(interceptor, signatureMap, interceptorMap);
return target;
}
}
Map<Method, List<Interceptor>> interceptorMap = new HashMap<>();
mapping(interceptor, signatureMap, interceptorMap);
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, interceptorMap));
}
return target;
}
/**
* @param interceptor Interceptor实例对象
* @param signatureMap 被拦截的接口有哪些方法是被拦截的
* @param interceptorMap 被拦截的方法,对应哪些Interceptor实例对象
*/
private static void mapping(Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap, Map<Method, List<Interceptor>> interceptorMap) {
for (Set<Method> methods : signatureMap.values()) {
for (Method method : methods) {
interceptorMap.computeIfAbsent(method, (key) -> new ArrayList<>()).add(interceptor);
}
}
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
List<Interceptor> interceptors = interceptorMap.get(method);
if (interceptors != null) {
return new InvocationList(interceptors, target, method, args).proceed();
}
//Set methods = signatureMap.get(method.getDeclaringClass());
//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);
}
}
private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
// issue #251
if (interceptsAnnotation == null) {
throw new PluginException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());
}
Signature[] sigs = interceptsAnnotation.value();
Map<Class<?>, Set<Method>> signatureMap = new HashMap<>();
for (Signature sig : sigs) {
Set<Method> methods = signatureMap.computeIfAbsent(sig.type(), k -> new HashSet<>());
try {
Method method = sig.type().getMethod(sig.method(), sig.args());
methods.add(method);
} catch (NoSuchMethodException e) {
throw new PluginException("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<>();
while (type != null) {
for (Class<?> c : type.getInterfaces()) {
if (signatureMap.containsKey(c)) {
interfaces.add(c);
}
}
type = type.getSuperclass();
}
return interfaces.toArray(new Class<?>[interfaces.size()]);
}
}
InvocationList
package org.apache.ibatis.plugin;
import org.apache.ibatis.reflection.ExceptionUtil;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
public class InvocationList extends Invocation {
private final List<Interceptor> interceptors;
int index = 0;
public InvocationList(List<Interceptor> interceptors, Object target, Method method, Object[] args) {
super(target, method, args);
this.interceptors = interceptors;
index = interceptors.size();
}
@Override
public Object proceed() throws InvocationTargetException, IllegalAccessException {
if ((index--) == 0) {
return super.proceed();
}
Interceptor interceptor = interceptors.get(index);
Object result = null;
try {
result = interceptor.intercept(this);
} catch (Throwable throwable) {
try {
throw ExceptionUtil.unwrapThrowable(throwable);
} catch (Throwable e) {
e.printStackTrace();
}
}
return result;
}
}