在第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. 插件的更多相关文章

  1. 《深入浅出MyBatis技术原理与实战》——6. MyBatis的解析和运行原理

    MyBatis的运行分为两大部分,第一部分是读取配置文件缓存到Configuration对象,用以创建SqlSessionFactory,第二部分是SqlSession的执行过程. 6.1 涉及的技术 ...

  2. 《深入浅出MyBatis技术原理与实战》——3. 配置

    要注意的是上面那些层次是不能够颠倒顺序的,否则MyBatis在解析文件的时候就会出现异常. 3.1 properties元素 properties是一个属性配置元素,让我们能在配置文件的上下文中使用它 ...

  3. 《深入浅出MyBatis技术原理与实战》——4. 映射器,5. 动态SQL

    4.1 映射器的主要元素 4.2 select元素 4.2.2 简易数据类型的例子 例如,我们需要统计一个姓氏的用户数量.应该把姓氏作为参数传递,而将结果设置为整型返回给调用者,如: 4.2.3 自动 ...

  4. 《深入浅出MyBatis技术原理与实战》——1.简介,2.入门

    1. 简介 Java程序都是通过JDBC连接数据库,但是只定义了接口规范,具体的实现交给各个数据库厂商去实现,因为每个数据库都有其特殊性.所以JDBC是一种桥接模式. 这里为什么说JDBC是一种桥接模 ...

  5. 深入浅出MyBatis技术原理与实战

    第1 章 MyBatis 简介..................................................................................... ...

  6. 深入浅出Mybatis技术原理与实战(杨开振)(带详细书签) PDF 下载 高清 完整版+源码

    (杨开振) 源码 IDE eclipse 建表语句也在里面 电子书+源码地址

  7. 2017.2.9 深入浅出MyBatis技术原理与实践-第八章 MyBatis-Spring(二)-----配置文件详解

    深入浅出MyBatis技术原理与实践-第八章 MyBatis-Spring(二) ------配置文件详解 8.2 MyBatis-Spring应用 8.2.1 概述 本文主要讲述通过注解配置MyBa ...

  8. 2MyBatis入门--深入浅出MyBatis技术原理与实践(笔记)

    什么是 MyBatis ? MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis ...

  9. 3MyBatis配置--深入浅出MyBatis技术原理与实践(笔记)

    XML 映射配置文件 configuration 配置 properties 属性 settings 设置 typeAliases 类型命名 typeHandlers 类型处理器 objectFact ...

随机推荐

  1. SRM13 T3 花六游鸟小(结论题)

    哇这题是真的喵,HR智商太高辣 这题的难点就是看了题解之后怎么证明题解里的结论... 结论①:深度大于logm的点肯定能达到最大值 证明:显然一个西瓜的属性里0数量一半1数量一半我们取到的1数量最少, ...

  2. Python中的结构化数据分析利器-Pandas简介

    Pandas是python的一个数据分析包,最初由AQR Capital Management于2008年4月开发,并于2009年底开源出来,目前由专注于Python数据包开发的PyData开发tea ...

  3. java 在centos6.5+eclipse环境下调用opencv实现sift算法

    java 在centos6.5+eclipse环境下调用opencv实现sift算法,代码如下: import org.opencv.core.Core; import org.opencv.core ...

  4. HDU 5650 异或

    so easy Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Sub ...

  5. 如何让浏览器在访问链接时不要带上referer

    function open_without_referrer(link){ document.body.appendChild(document.createElement('iframe')).sr ...

  6. Spring知识点复习

    Spring知识点复习 一.专业术语 侵入式设计 引入框架,对现有的类的结构有影响,即需要实现或继承某些特定类.如:Struts框架 非侵入式设计 引入框架,对现有的类结构没有影响.如:Hiberna ...

  7. DataGridView导出到Word

    #region 使用Interop.Word.dll将DataGridView导出到Word /// <summary> /// 使用Interop.Word.dll将DataGridVi ...

  8. 9.python爬虫--pyspider

    pyspider简介 PySpider:一个国人编写的强大的网络爬虫系统并带有强大的WebUI.采用Python语言编写,分布式架构,支持多种数据库后端,强大的WebUI支持脚本编辑器,任务监视器,项 ...

  9. 删除linux上7天前后缀名.sql的文件

    #!/bin/bash#delete the file of 7 days agofind /data/mysqlbackup/ -mtime +7 -name "*.sql" - ...

  10. 苹果API常用英语名词---iOS-Apple苹果官方文档翻译

    本系列所有开发文档翻译链接地址:iOS7开发-Apple苹果iPhone开发Xcode官方文档翻译PDF下载地址 苹果API常用英语名词0. indicating 决定1.in order to 以便 ...