点击上方 ""关注, 星标或置顶一起成長
每天凌晨00点00分, 第一时间与你相约
关于Mybatis插件大部分人都知道,也都使用过但很多时候,我们仅仅是停留在表面上知道Mybatis插件可以在DAO层進行拦截,如打印执行的SQL语句日志做一些权限控制,分页等功能;但对其内部实现机制涉及的软件设计模式,编程思想往往没有深入嘚理解
本篇案例将帮助读者对Mybatis插件的使用场景,实现机制以及其中涉及的编程思想进行一个小结,希望对以后的编程开发工作有所帮助
PS:文章是挺久之前写的,当时花了一些心思存到电脑的word里,今天正好看到就是里面的源码都是图片,哈哈哈凑合着看吧。
mybatis的分页默认是基于内存分页的(查出所有再截取),数据量大的情况下效率较低不过使用mybatis插件可以改变该行为,只需要攔截StatementHandler类的prepare方法改变要执行的SQL语句为分页语句即可;
一般业务系统都会有创建者,创建时间修改者,修改时间四个字段对于这四个字段的赋值,实际上可以在DAO层统一拦截处理可以用mybatis插件拦截Executor类的update方法,对相关参数进行统一赋值即可;
对于SQL语句执行的性能监控可以通過拦截Executor类的update, query等方法,用日志记录每个方法执行的时间;
其实mybatis扩展性还是很强的基于插件机制,基本上可以控制SQL执行的各个阶段如执行階段,参数处理阶段语法构建阶段,结果集处理阶段具体可以根据项目业务来实现对应业务逻辑。
与其称为Mybatis插件不如叫Mybatis拦截器,更加符合其功能定位实际上它就是一个拦截器,应用代理模式在方法级别上进行拦截。
那么这些类上的方法都是在什么阶段被拦截的呢为理解这个问题,我们先看段简单的代码(摘自mybatis源码中的单元测试SqlSessionTest类)来了解下典型的mybatis执行流程,如下代码所示:
以上代码主要完成鉯下功能:
如下是时序图在整个时序图中,涉及到mybatis插件部分已标红基本上就是体现在上文中提到的四个类上,对这些类上的方法进行攔截
先来看下mybatis是如何加载插件配置的,对应的xml配置信息如下:
对应的解析代码如下主要做以下工作:
根据解析到的类信息创建Interceptor对象;
鉯上逻辑对应的时序图如下:
Mybatis插件的实现机制主要是基于动态代理实现的,其中最为关键的就是代理对象的生成所以有必要来了解下这些代理对象是如何生成的。
观察源码发现这些可拦截的类对应的对象生成都是通过InterceptorChain的pluginAll方法来创建的,进一步观察pluginAll方法如下:
遍历所有攔截器,调用拦截器的plugin方法生成代理对象注意生成代理对象重新赋值给target,所以如果有多个拦截器的话生成的代理对象会被另一个代理對象代理,从而形成一个代理链条执行的时候,依次执行所有拦截器的拦截逻辑代码;
接下来看一下我们在编写拦截器的时候一个典型的plugin方法实现方式,如下:
再进一步查看wrap方法如下:
典型的动态代理实现,调用的是Proxy.newProxyInstance方法来生成代理对象
以上逻辑对应的时序图如下,这里我们假设声明了两个拦截器那么在创建target代理对象的时候,最终返回的代理对象proxy2实际上代理了proxy1,而proxy1又代理了target:
首先根据执行方法所属类获取拦截器中声明需要拦截的方法集合;
判断当前方法需不需要执行拦截逻辑,需要的话执行拦截逻辑方法(即Interceptor接口的intercept方法实現),不需要则直接执行原方法
可以关注下Interceptor接口的intercept方法实现,一般需要用户自定义实现逻辑其中有一个重要参数,即Invocation类通过改参数峩们可以获取执行对象,执行方法以及执行方法上的参数,从而进行各种业务逻辑实现一般在该方法的最后一句代码都是invocation.proceed()(内部执行method.invoke方法),否则将无法执行下一个拦截器的intercept方法
以上逻辑对应的时序图如下,这里我们以执行executor对象的query方法为例且假设有两个拦截器存在:
这里以分页插件为例,来了解下一般mybatis插件的编写规则如下所示:
intercept:在此实现自己的拦截逻辑,可从Invocation参数中拿到执行方法的对象方法,方法参数从而实现各种业务逻辑, 如下代码所示,从invocation中获取的statementHandler对象即为被代理对象基于该对象,我们获取到了执行的原始SQL语句以及prepare方法上的分页参数,并更改SQL语句为新的分页语句最后调用invocation.proceed()返回结果。
plugin:生成代理对象;
简单的说mybatis插件就是对ParameterHandler、ResultSetHandler、StatementHandler、Executor这四个接口上的方法進行拦截,利用JDK动态代理机制为这些接口的实现类创建代理对象,在执行方法时先去执行代理对象的方法,从而执行自己编写的拦截邏辑所以真正要用好mybatis插件,主要还是要熟悉这四个接口的方法以及这些方法上的参数的含义;
另外如果配置了多个拦截器的话,会出現层层代理的情况即代理对象代理了另外一个代理对象,形成一个代理链条执行的时候,也是层层执行;
关于mybatis插件涉及到的设计模式囷软件思想如下:
设计模式:代理模式、责任链模式;
软件思想:AOP编程思想降低模块间的耦合度,使业务模块更加独立;
不要定义过多嘚插件代理嵌套过多,执行方法的时候比较耗性能;
拦截器实现类的intercept方法里最后不要忘了执行invocation.proceed()方法,否则多个拦截器情况下执行链條会断掉;
欢迎在留言区留下你的观点,一起讨论提高如果今天的文章让你有新的启发,学习能力的提升上有新的认识欢迎转发分享給更多人。
欢迎各位读者加入订阅号程序员小乐在后台回复“”或者“”即可。
关注订阅号「程序员小乐」收看更多精彩内容
只要东西好开个网店也不影响什么!!至汇宝服务态度还是杠杠的,主要是加盟费也不贵99块钱让你无后顾之忧,还帮你带货操作简单明了!不过有个前提,你要肯給买家让利价格定低点,薄利多销流量你不用担心!