自定义拦截器Interceptor原理-Java动态代理
Mybatis中,我们想要扩展,必须实现Interceptor接口:
代码语言:javascript复制public interface Interceptor {
Object intercept(Invocation invocation) throws Throwable;
default Object plugin(Object target) {
return Plugin.wrap(target, this);
}
default void setProperties(Properties properties) {
// NOP
}
}
intercept()方法里需要实现我们自定义业务逻辑处理。
plugin()方法提供了统一代理类生成入口:
代码语言:javascript复制org.apache.ibatis.plugin.Plugin#wrap
主要功能是:生成代理类,invoke方法会匹配拦截器配置信息,调用我们自定义的拦截器中的intercept()方法。
代码语言:javascript复制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-为哪些功能生成了代理类
动态代理生成调用工具类入口:
代码语言:javascript复制org.apache.ibatis.plugin.InterceptorChain#pluginAll
ParameterHandler、ResultSetHandler、StatementHandler、Executor都为其生成了代理类。
自定义拦截器Interceptor-应用场景
拦截器可以拦截ParameterHandler、ResultSetHandler、StatementHandler、Executor的执行,我们可以实现:
1、分页插件;
2、Sql语句分析,可以防止全表更新、删除语句执行;
3、字段加密、解密;
4、dao执行耗时统计埋点、慢sql分析上报;
5、动态数据源切换;
等等各种场景。
感兴趣的可以去了解MyBatis-Plus一系列开源组件,很多功能都是自定义拦截器Interceptor实现的。