为什么说mybatis拦截器基于动态代理和责任链模式实现?

总所周知,mybatis拦截器功能是基于动态代理模式和责任链模式实现的,具体如何实现我们可以跟进代码一探究竟。

1、动态代理模式:

  1. 在项目mapper中找一个查询方法(返回对象是List集合的),debug进入,一直走到org.apache.ibatis.session.defaults.DefaultSqlSession#selectList方法,如下图

执行器是代理对象

  1. 由上图可知,执行器excutor是一个代理对象Proxy,所以执行executor类的实例方法(如图query方法)时会进到plugin类的invoke方法,plugin是一个InvocationHandler——动态代理模式(看不懂可以补下java动态代理知识点)

拦截器作为invocationHandler的成员变量备用

  1. 如上图所示,拦截器类inteceptor是plugin的成员变量,在执行动态代理invoke方法时会调用拦截器inteceptor的intercept方法,即我们自己定义的拦截器的方法。下图是自定义mybatis拦截器,可以看到实现了interceptor接口的intercept的方法
    在这里插入图片描述
  2. 如下图,类似AOP切面技术,在自定义拦截器的方法中,我们能获取到mybatis查询、新增、修改方法中的所有参数对象,比如查询sql语句、更新sql语句、各种参数等,并且根据需要修改他们。
    在这里插入图片描述

这就是拦截器基于动态代理实现自定义逻辑的本质。那么这种代理对象又是如何生成的那,这就不得不提到实现拦截器的另一种设计模式,责任链模式。

2、责任链模式

自定义拦截器可以有多个,满足条件的拦截器会被链式调用,这种模式就是基于责任链模式实现的,实现的逻辑如下:

  1. 如下图,在生成执行器executor时,将executor传入了interceptorChain的pluginAll方法中进行包装(类:org.apache.ibatis.session.Configuration)
    在这里插入图片描述

  2. 如下图,通过pluginAll方法可以看到,程序会遍历所有的interceptor(自定义的MyBatis拦截器),并调用拦截器的plugin方法包装executor,而且包装过后的executor会作为参数传到下一个interceptor中继续包装,一层包一层,直到把所有拦截器包进去。最终在调用executor的方法时,由于方法弹栈就会从最内部的对象一直链式执行到最外部的对象,这就是最经典的链式调用
    在这里插入图片描述

  3. 接下来跟进拦截器的plugin方法,该方法会调用plugin类的wrap方法,看名字可知道是一个包装方法,点进去看下是如何包装executor的。如下图方法所示,参数target就是传入的executor或者已经包装过的executor,interceptor就是自定义的mybatis拦截器
    在这里插入图片描述

  4. 在包装方法中我们可以看到,最终返回了一个executor的代理对象,其中interceptor作为参数传入了代理对象中,即在动态代理章节说的,拦截器传入到代理对象内部并在执行代理方法invoke时被调用

以上,就是mybatis拦截器基于动态代理和责任链模式实现的原理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值