目录
2. 自定义插件的编写逻辑:根据Mybatis规则 编写一个拦截器,在拦截器内部加入自定义增强功能
2.2 拦截器还要配置到mybatis里面,这里使用注解@Intercepts
上一篇中的Mybatis底层的四个处理器:StatementHandler 、ParameterHandler、ResultSetHandler、 TypeHandler
插件也涉及到4个核心对象:StatementHandler 、ParameterHandler、ResultSetHandler、Executor
回顾mybatis动态代理对象进行增删改查操作

mapper.queryStudentById()方法添加断点,调试进入方法内部
调用了invoke()方法,

进入execute()方法

进入selectOne()方法

进入selectList()方法

进入executor.query()方法


进入delegate.query()方法

进入queryFromDatabase()方法

进入doQuery()方法,在该方法可以看到我们的核心对象:StatementHandler

进入newStatementHandler(),把处理器statementHandler给interceptorChain.pluginAll(),该方法增强处理器statementHandler

拦截器类似于如下逻辑:

进入interceptorChain.pluginAll();

可以看到拦截器Interceptor接口在org.apache.ibatis.plugin包下

上诉拦截器,4个核心对象(StatementHandler 、ParameterHandler、ResultSetHandler、Executor)都有
四大核心对象:都涉及到了拦截器 用于增强 ,四大核心对象都包含了 该增强操作
自定义插件编写步骤:

实现刚刚提到的拦截器:Interceptor接口,注意在org.apache.ibatis.plugin接口中:


可以看到interceptor接口有3个方法:intercepted()、plugin()、setProperties()。
1. 先来看intercept()方法的放行方法:invoccation.proceed()


2. 再来看plugin()方法
plugin()方法将拦截器中定义的增强功能和4大核心对象封装成一个整体

3. 最后setProperties()方法

@Intercepts注解中使用{}添加@Signature注解
拦截器可以拦截4大核心对象(StatementHandler、ParameterHandler、ResultSetHandler、Execute)其中一个
通过type属性可以配置

这里我们拦截StatementHandler的query()方法

拦截上面的query(Statement var1,ResultHandler var2)方法
上面代码args的值给错了,第二个参数应该是ResultHandler类型,在org.apache.ibatis.session.ResultHandler包下

完整代码:
- package com.lyx.mybatis.interceptors;
-
- import org.apache.ibatis.executor.statement.StatementHandler;
- import org.apache.ibatis.plugin.*;
- import org.apache.ibatis.session.ResultHandler;
- import java.sql.Statement;
- import java.util.Properties;
-
- @Intercepts({
- @Signature(type = StatementHandler.class,
- method = "query",
- args = {Statement.class, ResultHandler.class})
- })
- public class MyInterceptor implements Interceptor {
- @Override
- public Object intercept(Invocation invocation) throws Throwable {
- System.out.println("这是一个拦截方法");
- Object proceed = invocation.proceed();
- System.out.println(proceed);
- return proceed;
- }
- //plugin()方法将拦截器中定义的增强功能和4大核心对象封装成一个整体
- @Override
- public Object plugin(Object o) {
- Object wrap = Plugin.wrap(o, this);
- return wrap;
- }
- //设置属性
- @Override
- public void setProperties(Properties properties) {
- System.out.println("设置属性"+properties);
- }
- }



黑色方框中为intercept()方法的输出内容,由于我的queryStudentById()方法到数据库里面查了2次数据,查询Student,再通过Student的外键查classroom表,所以intercept()方法执行两次。并打印Object proceed;
刚刚plugin()方法没有打印信息,现在添加上,测试类改为UserTest,输出如下:可以看到plugin()方法执行了4次--->plugin()方法把拦截器和4大核心对象进行封装时会每一个都尝试封装一下


在mybatis-config.xml文件中配置:

测试 
分析:

编写多个拦截器时,执行顺序和
配置顺序一致
例:
select * from student ➔ 拦截器 ➔ select * from student limit 3,5(例如分页插件)
select * from student where Id = 1 ➔ 拦截器 ➔ select * from student where Id = 3
为MyInterceptor类的intercept()方法添加如下
- Object target = invocation.getTarget();
- System.out.println("目标对象"+target);
测试运行:

看到target是RoutingStatementHandler类型

再添加代码:
- MetaObject metaObject = SystemMetaObject.forObject(target);
- metaObject.getValue("parameterHandler.parameterObject");
metaObject .getValue("xxx") :该方法可以获取RoutingStatementHandler 对象
从而通过RoutingStatementHandler.getBoundSql()获取到XxxMapper.xml中的sql:
metaObject.getValue("parameterHandler.boundsql.sql")

通过RoutingStatementHandler.getParameterHandler()取到XxxMapper.xml中的sql的参数值:
metaObject.getValue("parameterHandler.parameterObject");

我们来获取一下queryUserById(12)方法的参数值:12

执行:

由此,我们可以通过拦截器去修改这个参数值
添加注解
@Intercepts({
@Signature(
type = ,
method = ,
args =
)
})


修改参数代码如下:

invocation.proceed();放行要最后写

执行:

改为11:

测试成功
以上方法通过metaObject.setValue("parameterHandler.parameterObject",2);修改了参数
也可以通过metaObject.setValue("parameterHandler.boundSql.sql","select * from..");

- package com.lyx.mybatis.interceptors;
-
- import org.apache.ibatis.executor.statement.RoutingStatementHandler;
- import org.apache.ibatis.executor.statement.StatementHandler;
- import org.apache.ibatis.plugin.*;
- import org.apache.ibatis.reflection.MetaObject;
- import org.apache.ibatis.reflection.SystemMetaObject;
- import org.apache.ibatis.session.ResultHandler;
-
- import java.sql.Statement;
- import java.util.Properties;
-
- @Intercepts({
- @Signature(type = StatementHandler.class,
- method = "parameterize",
- args = Statement.class)
- })
- public class MyInterceptor implements Interceptor {
- @Override
- public Object intercept(Invocation invocation) throws Throwable {
- Object target = invocation.getTarget();
- MetaObject metaObject = SystemMetaObject.forObject(target);
- Object value = metaObject.getValue("parameterHandler.parameterObject");
- System.out.println("方法的参数值为:"+value);
-
- metaObject.setValue("parameterHandler.parameterObject",11);
- Object value2 = metaObject.getValue("parameterHandler.parameterObject");
- System.out.println("修改后方法的参数值为:"+value2);
-
- Object proceed = invocation.proceed();
- System.out.println(proceed);
- return proceed;
- }
-
- @Override
- public Object plugin(Object o) {
- Object wrap = Plugin.wrap(o, this);
- System.out.println("这是plugin : " + wrap);
- return wrap;
- }
-
- @Override
- public void setProperties(Properties properties) {
- System.out.println("这是设置属性" + properties);
- }
- }