Mybatis的拦截器设计真的太优雅啦!

文章详细探讨了Mybatis中注册插件的过程,特别是拦截器的代理实现。通过分析newExecutor和pluginAll方法,揭示了Mybatis如何构建拦截器链。拦截器的顺序与注册顺序相反,且在拦截Executor的query方法时需要注意参数不同的方法调用顺序,以确保所有拦截器都能生效。
摘要由CSDN通过智能技术生成

最近想研究一下mybatis如何注册插件的,发现Mybatis的拦截器是用代理实现的,写法再一次被惊艳到,下面是我的一些debug笔记和思考笔记笔记

mybatis通过默认工厂创建sqlsession的时候,会去创建一个Executor的代理类

通过一个select方法观察到。mybatis在执行selectList方法的时候, 产生了如下的调用栈

 

在执行这个方法newExecutor的时候,会根据ExecutorType去new自己写好的Executor实现,然后会去调用executor = (Executor) interceptorChain.pluginAll(executor);这个关键方法注册所有的拦截器

点进去pluginAll(executor)这个方法

会发现,InterceptorChain遍历所有拦截器都去调用它的plugin方法(父接口有默认的plugin实现),再次点进去plugin方法。发现他调用了Plugin.wrap方法。

在这个方法的第一行出现了getSignatureMap方法,debug后发现这个方法处理了自己写的interceptor类的注解里面包含的class和目标方法(getSignatureMap通过注解里面的类名和方法参数找到了具体应该拦截到的方法(Method method =sig.type().getMethod(sig.method(), sig.args());),如图这个方法结束后把所有参数都放到map集合中去

到这里,可以得出回到wrap方法。这个方法是一个把所有的拦截器一一组成一个的代理链的方法,他通过代理最初的自己写好的Executor接口的类,如果拦截器注解标注的接口,和要被代理的类如果有交集的话,接回就会继续生成代理并返回一个代理类,如果不是的话就返回自己target本身,这样一个链条式的代理类就生成了。起初没看明白动态的链式拦截器是怎么生成的,其比较关键的就是在Plugin类的wrap方法上,不断把自己作为成员属性传入Plugin,生成新的代理对象。然后在执行代理方法的时候。将自身的target传入invoke方法,因为target是下一个代理对象,所以就又会继续执行它的method,被invoke方法继续往下代理,然后又是相同的流程,直到最后的目标方法被执行,确实比较难理解,但总之就是套娃。。。。。。

再看一个设计的精妙的点,当代理拦截到想要的方法时,会去调用拦截器的intercept方法,并把被代理的方法,代理链的下一个代理对象(注意是下一个代理对象,不是当前代理对象)和method需要的参数方法封装成了Invocation传给拦截器接受,拦截器在这里可以执行自己自定义的方法后决定调用链要不要继续继续往下执行。(调用Invocation的proceed方法就可以往下执行了)

还有一个比较重要的点,就是自己在书写拦截器的时候,拦截的Exectur接口的query方法有两个,拦截器的执行顺序时和自己的注册顺序是相反的,比如说有拦截器先后注册了1,2,3,那么执行顺序是3,2,1,query,1,2,3,因为先注册的在interceptChain的pluginAll方法里面遍历的顺序最先。

在Mybatis自己写好的Exectur实现类里面,四个参数的query方法最终调用了6个参数的query方法。也就是说,如果某个拦截四个参数的query方法的时候,又去调用了6个参数的query方法,就会导致在这个拦截器后面的拦截器拦截不到四个参数的方法,导致拦截器失效。

所以这样的话,为了使所有的拦截器都生效,就把所有拦截四个参数的拦截器放在6个参数的query方法前面,拦截6个参数的拦截器放在6个参数的query后面就可以了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
sqltoy-orm是比hibernate+myBatis更加贴合项目orm框架,具有hibernate增删改的便捷性同时也具有比myBatis更加灵活优雅的自定义sql查询功能。 sqltoy-orm支持以下数据库: oracle 从oracle11g到19c db2 9.5+,建议从10.5 开始 mysql 支持5.6、5.7、8.0 版本 postgresql 支持9.5 以及以上版本 sqlserver 支持2008到2019版本,建议使用2012或以上版本 sqlite sybase_iq 支持15.4以上版本,建议使用16版本 elasticsearch 只支持查询,版本支持5.7+版本,建议使用7.3以上版本 clickhouse mongodb (只支持查询) sqltoy-orm特性: 1、根本上杜绝了sql注入问题,sql支持写注释、sql文件动态更新检测,开发sql变更会自动重载。 2、最直观的sql编写模式,当查询条件稍微复杂一点的时候就会体现价值,后期变更维护的时候尤为凸显。 3、极为强大的缓存翻译查询:巧妙的结合缓存减少查询语句表关联,极大简化sql和提升性能。 4、最强大的分页查询:很多人第一次了解到何为快速分页、分页优化这种极为巧妙的处理,还有在count语句上的极度优化。 5、跨数据库函数方言替换,如:isnull/ifnull/nvl、substr/substring 等不同数据库。 sqltoy-orm特点: 1、最优雅直观的sql编写模式 2、天然防止sql注入,执行过程 3、最强大的分页查询 4、最巧妙的缓存应用,将多表关联查询尽量变成单表 5、跨数据库 6、提供行列转换(数据旋转),避免写复杂的sql或存储过程,用算法来化解对sql的高要求,同时实现数据库无关(不管是mysql还是sqlserver) 7、提供分组汇总求平均算法(用算法代替sql避免跨数据库语法不一致) 8、分库分表 9、五种非数据库相关主键生成策略 10、elastic原生查询支持 11、elasticsearch-sql 插件模式sql模式支持     sqltoy-orm框架系统 更新日志: v4.18.22 1、在findEntity中EntityQuery可以设置fetchSize 2、在sqltoyContext中可以全局设置fetchSize,例如 spring.sqltoy.fetchSize=200 3、convertType 支持空集合返回空集合 4、针对一些特殊原因导致表名是数据库关键词的处理支持
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值