为了账号安全,请及时绑定邮箱和手机立即绑定

mybatis的扩展实现源码解读

标签:
Java

最近项目中需要用到mybatis的扩展,就深入看了下mybatis的实现,对其灵活性和扩展性的设计思想还是非常佩服的

 

首先说一下mybatis的拦截器使用方法:继承其Intercepter接口,实现org.apache.ibatis.plugin.Interceptor#intercept方法,在其中或者对其要执行的方法进行拦截,或者对返回值进行解析

同时基于org.apache.ibatis.plugin.Intercepts和org.apache.ibatis.plugin.Signature这两个注解来决定,对哪些执行器的哪些方法进行拦截

 

先看下拦截器的核心接口

?


public interface Interceptor {   Object intercept(Invocation invocation) throws Throwable;   Object plugin(Object target);   void setProperties(Properties properties); }

其中intercept方法是核心方法,拦截器的实现,plugin方法是用于配置哪些对哪些执行器进行拦截

 

继续看源码,可以看到mybatis的拦截是使用了jdk的动态代理实现的,本质上是一种代理机制

?


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

 

mybatis的这个Plugin就是代理类,这个代理类是在org.apache.ibatis.plugin.Interceptor#plugin方法中初始化的(调用org.apache.ibatis.plugin.Plugin#wrap),一个Plugin包含一个Intercepter,以及该Intercepter相关的注解配置信息,当对拦截对象的对应方法进行执行的时候,都会根据这些注解配置来判断是否需要执行该代理拦截(org.apache.ibatis.plugin.Plugin#invoke)

 

再看下plugin是如何被加载的:

?


public class InterceptorChain {   private final List<Interceptor> interceptors = new ArrayList<Interceptor>();   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);  } }

org.apache.ibatis.plugin.Interceptor#plugin是在org.apache.ibatis.plugin.InterceptorChain#pluginAll方法中调用的,我们可以看到,如果一个应用中注册了多个拦截器,那么实际上是会进行一个for循环的加载,由于上面说到了,加载一次,本质上是对mybatis的执行期进行一次代理包装,那么加载多次的话,就会代理包装多次,实际上就是一种多重代理了,这样就保证了每次调用都会按照代理顺序进行调用和返回的处理

可以看到,在做这些mybatis执行器初始化的时候,都会进行拦截器链的加载

 

至此,mybatis基于jdk动态代理的扩展实现方法就了解清楚了,其灵活性在于,它抽象了执行器的概念,并且拦截器的拦截方法也是固定的,我们可以对不同执行器的不同方法进行拦截,而对这些扩展点进行扩展却不用写多个方法实现多个方法,只需要实现一个接口就可以搞定了!

 

原文出处:https://www.cnblogs.com/cishengchongyan/p/10208040.html 

作者:此生重演  

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消