5分钟!彻底搞懂MyBatis插件+PageHelper原理( 二 )


5分钟!彻底搞懂MyBatis插件+PageHelper原理

文章插图
 
再次点击进去:
5分钟!彻底搞懂MyBatis插件+PageHelper原理

文章插图
 
到这里我们是不是发现很熟悉,没错,这就是我们上面示例中重写的方法,而plugin方法是接口中的一个默认方法 。
这个方法是关键,我们进去看看:
5分钟!彻底搞懂MyBatis插件+PageHelper原理

文章插图
 
可以看到这个方法的逻辑也很简单,但是需要注意的是MyBatis插件是通过JDK动态代理来实现的,而JDK动态代理的条件就是被代理对象必须要有接口,这一点和Spring中不太一样,Spring中是如果有接口就采用JDK动态代理,没有接口就是用CGLIB动态代理 。
关于动态代理,想详细了解的可以点击这里 。
正因为MyBatis的插件只使用了JDK动态代理,所以我们上面才强调了一定要实现Interceptor接口 。
而代理之后汇之星Plugin的invoke方法,我们最后再来看看invoke方法:
5分钟!彻底搞懂MyBatis插件+PageHelper原理

文章插图
 
而最终执行的intercept方法,就是我们上面示例中重写的方法 。
其他对象插件解析接下来我们再看看StatementHandler,StatementHandler是在Executor中的doQuery方法创建的,其实这个原理就是一样的了,找到初始化StatementHandler对象的方法:
5分钟!彻底搞懂MyBatis插件+PageHelper原理

文章插图
 
进去之后里面执行的也是pluginAll方法:
5分钟!彻底搞懂MyBatis插件+PageHelper原理

文章插图
 
其他两个对象就不在举例了,其实搜一下全局就很明显了:
PS:
5分钟!彻底搞懂MyBatis插件+PageHelper原理

文章插图
 
四个对象初始化的时候都会调用pluginAll来进行判定是否有被代理 。
插件执行流程下面就是实现了插件之后的执行时序图:
5分钟!彻底搞懂MyBatis插件+PageHelper原理

文章插图
 
假如一个对象被代理很多次一个对象是否可以被多个代理对象进行代理?也就是说同一个对象的同一个方法是否可以被多个拦截器进行拦截?
答案是肯定的,因为被代理对象是被加入到list,所以我们配置在最前面的拦截器最先被代理,但是执行的时候却是最外层的先执行 。
具体点:
假如依次定义了三个插件:插件A,插件B和插件C 。
那么List中就会按顺序存储:插件A,插件B和插件C,而解析的时候是遍历list,所以解析的时候也是按照:插件A,插件B和插件C的顺序,但是执行的时候就要反过来了,执行的时候是按照:插件C,插件B和插件A的顺序进行执行 。
PageHelper插件的使用上面我们了解了在MyBatis中的插件是如何定义以及MyBatis中是如何处理插件的,接下来我们就以经典分页插件PageHelper为例来进一步加深理解 。
首先我们看看PageHelper的用法:
package com.lonelyWolf.mybatis;import com.alibaba.fastjson.JSONObject;import com.github.pagehelper.Page;import com.github.pagehelper.PageHelper;import com.github.pagehelper.PageInfo;import com.lonelyWolf.mybatis.mapper.UserMapper;import com.lonelyWolf.mybatis.model.LwUser;import org.apache.ibatis.executor.result.DefaultResultHandler;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.ResultHandler;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;import java.io.InputStream;import java.util.List;public class MyBatisByPageHelp {public static void main(String[] args) throws IOException {String resource = "mybatis-config.xml";//读取mybatis-config配置文件InputStream inputStream = Resources.getResourceAsStream(resource);//创建SqlSessionFactory对象SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//创建SqlSession对象SqlSession session = sqlSessionFactory.openSession();PageHelper.startPage(0,10);UserMapper userMapper = session.getMapper(UserMapper.class);List<LwUser> userList = userMapper.listAllUser();PageInfo<LwUser> pageList = new PageInfo<>(userList);System.out.println(null == pageList ? "": JSONObject.toJSONString(pageList));}}输出如下结果:
5分钟!彻底搞懂MyBatis插件+PageHelper原理

文章插图
 
可以看到对象已经被分页,那么这是如何做到的呢?
PageHelper插件原理我们上面提到,要实现插件必须要实现MyBatis提供的Interceptor接口,所以我们去找一下,发现PageHeler实现了Interceptor:


推荐阅读