《深入浅出MyBatis技术原理与实战》——7. 插件
在第6章讨论了四大运行对象的运行过程,在Configuration对象的创建方法里我们看到了MyBatis用责任链去封装它们。
7.1 插件接口
在MyBatis中使用插件,我们必须使用接口Interceptor,先来看看它的定义和各个方法的含义:


在接口各中,运用了3个方法,这3个方法的含义是:

这里看到了插件的骨架,这样的模式我们称为模版模式,就是提供一个骨架,并且告知骨架中的方法是干什么用的,由开发者来完成它。
7.2 插件的初始化
插件的初始化实在MyBatis初始化的时候完成的,这点可以通过XMLConfigBuilder中的代码知道:


在解析配置文件的时候,在MyBatis的上下文初始化过程中,就开始读入插件节点和我们配置的参数,同时使用反射技术生成对应的插件实例,然后调用插件方法中的setProperties方法,设置我们配置的参数,然后将插件实例保存到配置对象中,以便读取和使用它。所以插件的实例对象是一开始就被初始化的,而不是用到的时候才初始化的,我们使用它的时候,直接拿出来就可以了,这样有助于性能的提高。
再来看看插件在Configuration对象里是怎样保存的:

InterceptorChain在Configuration里面是一个属性,它里面有个addInterceptor方法:

显然,完成初始化的插件就保存在这个List对象里面等待将其取出使用。
7.3 插件的代理和反射设计
插件用的是责任链模式。就是一个对象,在MyBatis中可能是四大对象中的一个,在多个角色中传递,处在传递链上的任何角色都有处理它的机会。
MyBatis的责任链是由InterceptorChain去定义的,MyBatis在创建执行器时用到这样的代码:

来看看pluginAll()方法是如何实现的:

plugin方法是生成代理对象的方法,当它取出插件的时候是从Configuration对象中去取的。从第一个对象(四大对象中的一个)开始,将对象传递给了plugin方法,然后返回一个代理,如果存在第二个插件,那么就拿到第一个代理对象的代理,传递给plugin方法再返回第一个代理对象的代理......以此类推,有多少个拦截器就生成多少个代理对象。这样有多少个拦截器就生成多少个代理对象。
MyBatis中提供了一个常用的工具类来生成代理对象,它便是Plugin类。Plugin类实现了InvocationHandler接口,采用的是JDK动态代理,我们首先看看这个类的两个十分重要的方法:


看以看到它是一个动态代理对象,其中wrap方法为我们生成这个对象的动态代理对象。至于invoke方法,如果使用这个类为插件生成代理对象,那么代理对象在调用方法的时候就会进入到invoke方法中。在invoke方法中,如果存在签名的拦截方法,插件的intercept方法就会被我们在这里调用,然后就返回结果。如果不存在签名的方法,那么将直接调度我们要执行的方法。
我们创建一个Invocation对象,其构造方法的参数包括被代理对象、方法及其参数。Invocation对象进行初始化,它有一个proceed()方法:


这个方法就是调度被代理对象的真实方法。现在假设有n个插件,我们知道第一个传递的参数是四大对象本身,然后调用一次wrap方法产生第一个代理对象,而这里的反射就是反射四大对象本身的真实方法。如果有第二个插件,我们会将第一个代理对象传递给wrap方法,生成第二个代理对象,这里的反射就是指第一个代理对象的invoke方法,依次类推直至最后一个代理对象。如果每一个代理对象都调用这个proceed方法,那么最后四大对象本身的方法也会被调用,只是它会从最后一个代理对象的invoke方法运行到第一个代理对象的invoke方法,直至四大对象的真实方法。
7.4 常用的工具类——MetaObject
可以有效的读取或者修改一些重要的对象属性。它有3个方法常常用到:


我们可以通过使用它来给四大对象的某些属性赋值从而满足我们的需要。例如,拦截StatementHandler对象,我们需要先获取她要执行的SQL修改它的一些值。这个时候我们可以使用MetaObject,如:

拦截的StatementHandler实际上是RoutingStatementHandler对象,它的delegate属性才是真实服务的StatementHandler,真实的StatementHandler有一个属性BoundSql,它下面又有一个属性sql。所以才有了路径delegate.boundSql.sql。我们就可以通过这个路径获取或者修改对应运行时的SQL。
7.5 插件开发过程实例
限制每一条SQL返回数据的行数。限制的行数是个可配置的参数,业务可以根据自己的需要去配置。
7.5.1 确定需要拦截的签名
从Plugin源码中我们可以看到它需要注册签名才能够运行插件。签名需要确定一些要素。
(1) 确定需要拦截的签名

那么我们需要拦截的是StatementHandler对象,应该在预编译SQL之前,修改SQL使得返回数量被限制。
(2) 拦截方法和参数
查询是通过Executor调度StatementHandler来完成的。调度StatementHandler的prepare方法预编译SQL,于是我们需要拦截的方法便是prepare方法,在此之前完成SQL的重新编译。先来看看那StatementHandler接口的定义:

以上的任何方法都可以被拦截。从接口的定义而言,prepare方法有一个参数Connection对象,因此我们按如下代码来设计拦截器:

其中@Intercepts说明它是一个拦截器。@Signature是注册拦截器签名的地方,只有签名满足条件才能被拦截,type可以使四大对象中的一个,这里是StatementHandler。method代表要拦截四大对象的某一种接口方法,而args则表示该方法的参数。
7.5.4 插件实例
限制查询返回的数据量。需要拦截的是StatementHandler对象




在setProperties方法中可以读入配置给插件的参数,一个是数据库的名称,另外一个是限制的记录数。在plugin方法里,使用了MyBatis提供的类来生成代理对象。那么插件就会进入plugin的invoke方法,它最后会使用到拦截器的intercept方法。现在我们需要在MyBatis配置文件里面配置才能运行这个插件:

注意:


《深入浅出MyBatis技术原理与实战》——7. 插件的更多相关文章
- 《深入浅出MyBatis技术原理与实战》——6. MyBatis的解析和运行原理
MyBatis的运行分为两大部分,第一部分是读取配置文件缓存到Configuration对象,用以创建SqlSessionFactory,第二部分是SqlSession的执行过程. 6.1 涉及的技术 ...
- 《深入浅出MyBatis技术原理与实战》——3. 配置
要注意的是上面那些层次是不能够颠倒顺序的,否则MyBatis在解析文件的时候就会出现异常. 3.1 properties元素 properties是一个属性配置元素,让我们能在配置文件的上下文中使用它 ...
- 《深入浅出MyBatis技术原理与实战》——4. 映射器,5. 动态SQL
4.1 映射器的主要元素 4.2 select元素 4.2.2 简易数据类型的例子 例如,我们需要统计一个姓氏的用户数量.应该把姓氏作为参数传递,而将结果设置为整型返回给调用者,如: 4.2.3 自动 ...
- 《深入浅出MyBatis技术原理与实战》——1.简介,2.入门
1. 简介 Java程序都是通过JDBC连接数据库,但是只定义了接口规范,具体的实现交给各个数据库厂商去实现,因为每个数据库都有其特殊性.所以JDBC是一种桥接模式. 这里为什么说JDBC是一种桥接模 ...
- 深入浅出MyBatis技术原理与实战
第1 章 MyBatis 简介..................................................................................... ...
- 深入浅出Mybatis技术原理与实战(杨开振)(带详细书签) PDF 下载 高清 完整版+源码
(杨开振) 源码 IDE eclipse 建表语句也在里面 电子书+源码地址
- 2017.2.9 深入浅出MyBatis技术原理与实践-第八章 MyBatis-Spring(二)-----配置文件详解
深入浅出MyBatis技术原理与实践-第八章 MyBatis-Spring(二) ------配置文件详解 8.2 MyBatis-Spring应用 8.2.1 概述 本文主要讲述通过注解配置MyBa ...
- 2MyBatis入门--深入浅出MyBatis技术原理与实践(笔记)
什么是 MyBatis ? MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis ...
- 3MyBatis配置--深入浅出MyBatis技术原理与实践(笔记)
XML 映射配置文件 configuration 配置 properties 属性 settings 设置 typeAliases 类型命名 typeHandlers 类型处理器 objectFact ...
随机推荐
- 爬虫实例——爬取煎蛋网OOXX频道(反反爬虫——伪装成浏览器)
煎蛋网在反爬虫方面做了不少工作,无法通过正常的方式爬取,比如用下面这段代码爬取无法得到我们想要的源代码. import requests url = 'http://jandan.net/ooxx' ...
- java访问Https服务的客户端示例
关于证书 1.每个人都可以使用一些证书生成工具为自己的https站点生成证书(比如JDK的keytool),大家称它为“自签名证书”,但是自己生成的证书是不被浏览器承认的,所以浏览器会报安全提示,要求 ...
- 在CentOS6.5 下安装并使用Java开发opencv的配置(一)
1) 安装gcc以及cmake等等乱七八糟的软件 yum install gcc yum install python yum install cmake yum groupinstall " ...
- A星寻路算法-Mind&Hand(C++)
//注1:Mind & Hand,MIT校训,这里指的理解与实现(动脑也动手) //注2:博文分为两部分:(1)理解部分,为参考其他优秀博文的摘要梳理:(2)代码部分,是C++代码实现的,源码 ...
- Linux网络监控工具nethogs
Linux网络监控工具nethogs 标签: 监控工具linux 2015-12-17 22:06 448人阅读 评论(0) 收藏 举报 分类: linux(40) 版权声明:本文为博主原创文章, ...
- React Mixin
为什么使用 Mixin ? React为了将同样的功能添加到多个组件当中,你需要将这些通用的功能包装成一个mixin,然后导入到你的模块中. 可以说,相比继承而已,React更喜欢这种组合的方式. 写 ...
- UIToolBar的半透明属性设置
UIToolBar的半透明属性设置style:Translucent(Ps:长得很像翻译translation) https://www.evernote.com/shard/s227/sh/ ...
- webpack4.x 入门一篇足矣
前言: webpack4出了以后,一些插件变化很大,和之前的版本使用方式不一样,新手入坑,本篇将介绍如何从一开始配置webpack4的开发版本,对css,js进行编译打包合并生成md5,CSS中的图片 ...
- 【洛谷 P1452】 Beauty Contest (二维凸包,旋转卡壳)
题目链接 旋转卡壳模板题把. 有时间再补总结吧. #include <cstdio> #include <cmath> #include <algorithm> u ...
- bzoj 1034 贪心
首先如果我们想取得分最高的话,肯定尽量赢,实在赢不了的话就耗掉对方最高的,那么就有了贪心策略,先排序,我方最弱的马和敌方最弱的相比,高的话赢掉,否则耗掉敌方最高的马. 对于一场比赛,总分是一定的,所以 ...