mybatis 插件原理

本文详细剖析了Mybatis插件的实现原理,基于JDK动态代理,通过InterceptorChain类的pluginAll方法遍历拦截器链,并在Plugin类中创建代理对象。重点介绍了如何自定义Mybatis插件,包括拦截器的编写、配置文件的设置以及测试过程,展示了分页插件的实现示例。
摘要由CSDN通过智能技术生成

1.Mybatis插件原理

Mybatis的插件,是采用责任链机制,通过JDK动态代理来实现的。默认情况下,Mybatis允许使用插件来拦截四个对象:

  1. Executor:执行CURD操作;
  2. StatementHandler:处理sql语句预编译,设置参数等相关工作;
  3. ParameterHandler:设置预编译参数用的;
  4. ResultSetHandler:处理结果集。

这个我们可以从Mybatis的源码中看到,例如下面创建Executor的时候,就是返回了一个代理Executor对象:

开始进入源码环节。

下面是InterceptorChain 类的源码:可以看到内部有一个拦截器链,调用pluginAll方法时,会遍历所有的拦截器的plugin方法

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);
  }

}

查看 Interceptor源码:它是一个接口,其plugin方法又调用了Plugin.wrap方法,继续跟入。

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
  }

}

Plugin源码:进到这里,思路就豁然开朗了,wrap方法里就是通过JDK动态代理创建了一个代理对象。下面我们逐行看下,都经过了哪些步骤。

/**
 *    Copyright 2009-2021 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.plugin;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.ibatis.reflection.ExceptionUtil;

/**
 * @author Clinton Begin
 */
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) {
    // 得到拦截器上的注解的 classType、 method、parameter参数的Map
    Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
    // 获取被代理的Class类型
    Class<?> type = target.getClass();
    // 找到signatureMap中包含的 type 的所有父类接口
    Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
    if (interfaces.length > 0) {
      // 创建一个代理对象
      return Proxy.newProxyInstance(
          typ
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值