通过 MyBatis 提供的弱小机制,应用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦挡的办法签名即可。
@Slf4j@Intercepts({ @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class} ), @Signature( type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class} ), @Signature( type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class} ), @Signature( type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class} ),})@Component@Order(-2)public class CustomizeInterceptor implements Interceptor { @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public Object intercept(Invocation invocation) throws Throwable { //获取代理对象 log.info("拦挡:{}", invocation.getMethod().getName()); return invocation.proceed(); }}
- MybatisConfiguration 中源码解析办法
public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; if (ExecutorType.BATCH == executorType) { executor = new MybatisBatchExecutor(this, transaction); } else if (ExecutorType.REUSE == executorType) { executor = new MybatisReuseExecutor(this, transaction); } else { executor = new MybatisSimpleExecutor(this, transaction); } if (cacheEnabled) { executor = new MybatisCachingExecutor(executor); } //插件拦截器链 executor = (Executor) interceptorChain.pluginAll(executor); return executor; } }
- InterceptorChain 中拦截器链条
private final List<Interceptor> interceptors = new ArrayList<>(); public Object pluginAll(Object target) { for (Interceptor interceptor : interceptors) { //调用 target = interceptor.plugin(target); } return target; } //调用接口 default Object plugin(Object target) { return Plugin.wrap(target, this); }
3.它又持续调用了Plugin的静态方法wrap
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) { //生成代理对象 动静代理 调用invoke return Proxy.newProxyInstance( type.getClassLoader(), interfaces, new Plugin(target, interceptor, signatureMap)); } return target; }
4.执行 拦挡
@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); } }
- 流程图
最终Executor不再是原来的类,而是它的代理类。newStatementHandler办法和newResultSetHandler办法的流程,也差不多,最终也是生成代理类
6.当Executor、StatementHandler、ParameterHandler、ResultSetHandler执行他们本人的办法时,实际上调用他们的代理类Plugin中的invoke办法
7.多个plugins 拦截器代理 后面的代理类被前面的拦截器又代理
套娃行为
所以,前面的将会代理后面的,——越外层的越先执行
8.多个插件的执行程序曾经明了了,那么插件外面办法的执行程序呢?
query->prepare->setParameters->handleResultSets
这个博客还是讲的很分明的
参考博客:https://blog.csdn.net/qq_18433441/article/details/84036317