Mybatis插件原理分析(二)
在上一篇中Mybatis插件原理分析(一)中我们主要介绍了一下Mybatis插件相关的几个类的源码,并对源码进行了一些解释,接下来我们通过一个简单的插件实现来对Mybatis插件的运行流程进行分析。
一、简单的插件MyInterceptor,源码如下:
/**
* 实现Interceptor的类必须使用注解@Intercepts,Plugin类中的getSignatureMap函数就是来解析这个注解
* 获得注解中的相关信息,比如拦截的method,拦截的接口实现类,以及method的函数参数等
*/
@Intercepts( {
@Signature(method = "query", type = Executor.class, args = {
MappedStatement.class, Object.class, RowBounds.class,
ResultHandler.class })})
public class MyInterceptor implements Interceptor {
//这个函数的最终结果是调用invocation.proceed()方法,调用目标类的method.invoke方法
@Override
public Object intercept(Invocation invocation) throws Throwable {
return invocation.proceed();
}
//这个方法的目的就是将目标类通过代理类Plugin的wrap方法来生成目标类
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// TODO Auto-generated method stub
}
}
二、mybatis的配文件中添加如下配置:
<plugins>
<plugin interceptor="com.tianjunwei.MyInterceptor"></plugin>
</plugins>
这样就完成了一个简单插件的实现工作。
三、运行流程
(1)在mybatis启动阶段,在Configuration类中的Executor、ParameterHandler、ResultSetHandler和StatementHandler的实现类初始化过程中会调用如下进行初始化:
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
在InterceptorChain类中调用pluginAll函数,会调用所有已经实现的Interceptor,例如我们刚实现的MyInterceptor类的plugin方法
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
MyInterceptor类中的plugin方法其实调用的是Plugin的wrap函数,wrap函数是用来生代理类的目标类的
//这个方法的目的就是将目标类通过代理类Plugin的wrap方法来生成目标类
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
Plugin类中的wrap实现如下,其目的就是生成目标类,这样Executor、ParameterHandler、ResultSetHandler和StatementHandler的实现类都是目标类
//一个静态方法,对一个目标对象进行包装,生成目标类。
public static Object wrap(Object target, Interceptor interceptor) {
//首先根据interceptor上面定义的注解 获取需要拦截的信息
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
Class<?> type = target.getClass();
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
//如果长度为>0 则返回代理类 否则不做处理
if (interfaces.length > 0) {
//创建JDK动态代理对象
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}
我们以Executor的实现类来说明,当调用Executor的query方法是,根据代理类机制会调用Plugin的invoke方法
在invoke方法中我们可以看,首先会判断目标类调用的方法是否是我们在实现的MyInterceptor的注解中进行了配置,如果配置了则会调用interceptor.intercept(new Invocation(target, method, args));,这样的话就是调用的MyInterceptor的intercept方法,否则则直接调用return method.invoke(target, args);,
//在执行Executor、ParameterHandler、ResultSetHandler和StatementHandler的实现类的方法时会调用这个方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
//通过method参数定义的类 去signatureMap当中查询需要拦截的方法集合
Set<Method> methods = signatureMap.get(method.getDeclaringClass());
//判断是否是需要拦截的方法,如果需要拦截的话就执行实现的Interceptor的intercept方法,执行完之后还是会执行method.invoke方法,不过是放到interceptor实现类中去实现了
if (methods != null && methods.contains(method)) {
return interceptor.intercept(new Invocation(target, method, args));
}
//不拦截 直接通过目标对象调用方法
return method.invoke(target, args);
} catch (Exception e) {
throw ExceptionUtil.unwrapThrowable(e);
}
}
因为在MyInterceptor的plugin方法中已经把MyInterceptor作为参数赋值给Plugin了,代码如下
//这个方法的目的就是将目标类通过代理类Plugin的wrap方法来生成目标类
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
总结:Mybatis的插件的原理就是对Executor、ParameterHandler、ResultSetHandler和StatementHandler的实现类通过Plugin代理来生成目标类,并且关联生成的目标类与实现的Interceptor类,这样在调用Executor、ParameterHandler、ResultSetHandler和StatementHandler的实现类方法时会调用Plugin类中的invoke方法,在调用invoke方法时会进行判断这个实现类是否需要我们实现的MyInterceptor来处理,如果是会调用MyInterceptor的interceptor方法,进行一些处理之后调用Invocation的proceed方法,其实际处理方法也是调用method.invoke方法,如果不需要MyInterceptor处理时则直接调用method.invoke方法,Mybatis巧妙的利用的JDK的代理机制,实现了对目标类和方法在调用之前的一些处理,提高了整个框架的灵活性。
Mybatis插件原理分析(二)的更多相关文章
- Mybatis插件原理分析(一)
我们首先介绍一下Mybatis插件相关的几个类,并对源码进行了简单的分析. Mybatis插件相关的接口或类有:Intercept.InterceptChain.Plugin和Invocation,这 ...
- Mybatis插件原理分析(三)分页插件
在Mybatis中插件最经常使用的是作为分页插件,接下来我们通过实现Interceptor来完成一个分页插件. 虽然Mybatis也提供了分页操作,通过在sqlSession的接口函数中设置RowBo ...
- Mybatis框架(8)---Mybatis插件原理
Mybatis插件原理 在实际开发过程中,我们经常使用的Mybaits插件就是分页插件了,通过分页插件我们可以在不用写count语句和limit的情况下就可以获取分页后的数据,给我们开发带来很大 的便 ...
- mybatis 插件原理
[传送门]:mybatis 插件原理
- MyBATIS插件原理第一篇——技术基础(反射和JDK动态代理)(转)
在介绍MyBATIS插件原理前我们需要先学习一下一些基础的知识,否则我们是很难理解MyBATIS的运行原理和插件原理的. MyBATIS最主要的是反射和动态代理技术,让我们首先先熟悉它们. 1:Jav ...
- (转载)Java NIO:NIO原理分析(二)
NIO中的两个核心对象:缓冲区和通道,在谈到缓冲区时,我们说缓冲区对象本质上是一个数组,但它其实是一个特殊的数组,缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变化情况,如果我们使用 ...
- Redis有序集内部实现原理分析(二)
Redis技术交流群481804090 Redis:https://github.com/zwjlpeng/Redis_Deep_Read 本篇博文紧随上篇Redis有序集内部实现原理分析,在这篇博文 ...
- Android 4.4 KitKat NotificationManagerService使用具体解释与原理分析(二)__原理分析
前置文章: <Android 4.4 KitKat NotificationManagerService使用具体解释与原理分析(一)__使用具体解释> 转载请务必注明出处:http://b ...
- Mybatis 插件原理解析
SqlSessionFactory 是 MyBatis 核心类之一,其重要功能是创建 MyBatis 的核心接口 SqlSession.MyBatis 通过 SqlSessionFactoryBuil ...
随机推荐
- Lintcode393 Best Time to Buy and Sell Stock IV solution 题解
[题目描述] Say you have an array for which the i th element is the price of a given stock on day i. Desi ...
- UDP网络编程
概念: UDP协议(用户数据报协议)是无连接,不可靠的,无序的.速度比较快, UDP协议以数据报作为数据传输的载体 进行数据传输时,首先将传输的数据定义成数据报(Datagram),在数据报中指明数据 ...
- 全网代理公开ip爬取(隐藏元素混淆+端口加密)
简述 本次要爬取的网站是全网代理,貌似还是代理ip类网站中比较有名的几个之一,其官网地址: http://www.goubanjia.com/. 对于这个网站的爬取是属于比较悲剧的,因为很久之前就写好 ...
- Go 语言运算符
运算符用于在程序运行时执行数学或逻辑运算. Go 语言内置的运算符有: 算术运算符 关系运算符 逻辑运算符 位运算符 赋值运算符 其他运算符 接下来让我们来详细看看各个运算符的介绍. 算术运算符 下表 ...
- ZooKeeper之(四)配置与命令
4.1 配置文件 ZooKeeper安装好之后,在安装目录的conf文件夹下可以找到一个名为"zoo_sample.cfg"的文件,是ZooKeeper配置文件的模板. ZooKe ...
- 实例演示如何在spring4.2.2中集成hibernate5.0.2并创建sessionFactory
本文地址:http://blog.csdn.net/sushengmiyan/article/details/49388209 文章作者:苏生米沿 本文目的:使用spring4.2.2集成hibern ...
- Linux 高性能服务器编程——Linux服务器程序规范
问题聚焦: 除了网络通信外,服务器程序通常还必须考虑许多其他细节问题,这些细节问题涉及面逛且零碎,而且基本上是模板式的,所以称之为服务器程序规范. 工欲善其事,必先利其器,这篇主要来探 ...
- Dynamics CRM FORM脚本库加载本地脚本
用传统的开发方式,js脚本都是保存在数据库中的,这样也方便迁移,但如果不想存数据库而是存在物理磁盘上,则可通过下述代码,将脚本存放在CRMWEB文件夹的某个路径下,每次都动态引用本地JS. funct ...
- HTTP状态码总结
HTTP状态码(HTTP Status Code)是用以表示网页服务器HTTP响应状态的3位数字代码.有些 App 端接口与 HTML 接口用的是同一个,所以做移动端开发也有必要了解一下HTTP状态码 ...
- RxJava(01-介绍与初体验)
转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51612415 本文出自:[openXu的博客] 目录: 一 简介 二 简单使用 初步探索 代 ...