一、拦截器加载配置
在configuration里面可以配置plugin,他是在XMLConfigBuilder装配进去的
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).newInstance();
interceptorInstance.setProperties(properties);
configuration.addInterceptor(interceptorInstance);
}
}
}
二、哪些位置可以加拦截器
在configuration里面,有四处位置可以添加拦截器:
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
executor = (Executor) interceptorChain.pluginAll(executor);
也就是说可以在参数、结果、声明、执行四处位置添加拦截器
可以看这里是拦截器链interceptorChain,所以可以同时加不同的拦截器
三、拦截器可以做哪些事情
动态修改参数(数据加密),动态修改结果集(数据解密)、动态修改声明处理(分表),动态修改执行器(去掉本地缓存参数)
例如,参数拦截器,参数加密;
@Intercepts({ @Signature(type = ParameterHandler.class, method = "setParameters", args = { PreparedStatement.class }) })
public class ParameterInterceptor implements Interceptor{
private static final String tag = ParameterInterceptor.class.getName();
private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
@Override
public Object intercept(Invocation invocation) throws Throwable {
ParameterHandler parameterHandler = (ParameterHandler)invocation.getTarget();
MetaObject metaParameterHandler= MetaObject.forObject(
parameterHandler, DEFAULT_OBJECT_FACTORY,
DEFAULT_OBJECT_WRAPPER_FACTORY);
Object parameterObj =metaParameterHandler
.getValue("parameterObject");
BoundSql boundSql = (BoundSql) metaParameterHandler
.getValue("boundSql");
MappedStatement mappedStatement = (MappedStatement) metaParameterHandler
.getValue("mappedStatement");
String id = mappedStatement.getId();
String className = id.substring(0, id.lastIndexOf("."));
Class<?> classObj = Class.forName(className);
//根据配置加密
TableSeg tableSeg = classObj.getAnnotation(TableSeg.class);
if(tableSeg!=null){
String[] fields = tableSeg.encryptFields();
if(fields.length>0){
EncryptParameter as = new EncryptParameterImpl(mappedStatement, parameterObj, boundSql);
as.encryptParamter(fields);
}
}
//继续执行
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
// 当目标类是ParameterHandler类型时,才包装目标类,否者直接返回目标本身,减少目标被代理的
// 次数
if (target instanceof ParameterHandler) {
return Plugin.wrap(target, this);
} else {
return target;
}
}
@Override
public void setProperties(Properties properties) {
// TODO Auto-generated method stub
}
}
四、拦截器原理
executor = (Executor) interceptorChain.pluginAll(executor);
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
可以看到返回的是插件包装后的对象,所有的拦截都会包装,而拦截器plugin由具体拦截器实现,拦截器都需要实现Interceptor接口:
public interface Interceptor {
Object intercept(Invocation invocation) throws Throwable;
Object plugin(Object target);
void setProperties(Properties properties);
}
plugin用于包装,因为所有的拦截器都会包装下,所以这个方法里面需要针对性的过滤下,什么拦截器就包装什么,比如ExecutorInterceptor拦截器:
@Override
public Object plugin(Object target) {
// 当目标类是Executor类型时,才包装目标类,否者直接返回目标本身,减少目标被代理的
// 次数
if (target instanceof Executor) {
return Plugin.wrap(target, this);
} else {
return target;
}
}
可以看到只有是Executor的时候才返回包装对象,其他的不管。
具体看Plugin.wrap(target, this)将对象怎么包装了。
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;
}
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
//获取拦截器拦截参数配置,也就是注解参数,例如:
//获取拦截器拦截参数配置,也就是注解参数,例如:
@Intercepts({ @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class,RowBounds.class,ResultHandler.class}) })
表示类型Executor,拦截方法query,参数类型
最后实际上他返回的是一个动态代理对象。没有接口的直接返回对象,
而执行方法调用的时候,调用的是代理的invoke方法,也就是plugin的invoke方法
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);
}
}
判断配置的方法是不是执行调用方法,如果是执行拦截器
intercept方法,不是直接执行方法调用
拦截器的
intercept方法也就是我们定义拦截器,自定义处理的方法。自定义方法可以通过
Invocation获取参数
在自定义方法中做完自己的事情最后需要执行,
//继续执行
return invocation.proceed();
而这个方法其实就是方法调用,也就是说动态代理就是提供了
自定义方法调用的一个时机。
return method.invoke(target, args);