博客
关于我
MyBatis的插件机制及其用法
阅读量:98 次
发布时间:2019-02-25

本文共 2726 字,大约阅读时间需要 9 分钟。

文章目录

1、前言

1.1 Mybatis四大对象

org.apache.ibatis.executor.parameter.ParameterHandler:处理SQL的参数对象

org.apache.ibatis.executor.resultset.ResultSetHandler:处理SQL的返回结果集
org.apache.ibatis.executor.statement.StatementHandler:数据库的处理对象,用于执行SQL语句
org.apache.ibatis.executor.Executor:MyBatis的执行器,用于执行增删改查操作

1.2 Mybatis插件

  与其称为Mybatis插件,不如叫Mybatis拦截器,更加符合其功能定位,实际上它就是一个拦截器,应用代理模式,在方法级别上进行拦截。

  支持拦截的方法:
  1、参数处理器ParameterHandler(getParameterObject、setParameters方法);
  2、结果集处理器ResultSetHandler(handleResultSets、handleOutputParameters等方法);
  3、SQL语法构建器StatementHandler(prepare、parameterize、batch、update、query等方法);
  4、执行器Executor(update、query、commit、rollback等方法);

1.3 拦截阶段

  那么这些类上的方法都是在什么阶段被拦截的呢?为理解这个问题,我们先看段简单的代码(摘自mybatis源码中的单元测试SqlSessionTest类),来了解下典型的mybatis执行流程,如下代码所示:

在这里插入图片描述
  以上代码主要完成以下功能:
  1、读取mybatis的xml配置文件信息
  2、通过SqlSessionFactoryBuilder创建SqlSessionFactory对象
  3、通过SqlSessionFactory获取SqlSession对象
  4、执行SqlSession对象的selectList方法,查询结果
  5、关闭SqlSession
  如下是时序图,在整个时序图中,涉及到mybatis插件部分已标红,基本上就是体现在上文中提到的四个类上,对这些类上的方法进行拦截。
在这里插入图片描述

2、源码分析

  源码分析只是加深理解,不想看的可以跳过直接看第三节的用法。

2.1 过程

  我们从四大对象的创建为入口,逐步分析整个插件的使用过程。

  以StatementHandler为例,找到它的源码:
在这里插入图片描述
  发现它是个接口,我们找到它的实现类:
在这里插入图片描述
  下面的xxxStatementHandler都继承了BaseStatementHandler,所以我们直接看BaseStatementHandler,观察它的构造方法:
在这里插入图片描述
  可以看到,在创建BaseStatementHandler时,也顺带创建了ParameterHandlerResultSetHandler,点进去看这两个对象的创建方法:
在这里插入图片描述
  发现这些可拦截的类对应的对象生成都是通过InterceptorChainpluginAll方法来创建的,进一步观察pluginAll方法,如下:
在这里插入图片描述
  遍历所有拦截器,调用拦截器的plugin方法生成代理对象,注意生成代理对象重新赋值给target,所以如果有多个拦截器的话,生成的代理对象会被另一个代理对象代理,从而形成一个代理链条,执行的时候,依次执行所有拦截器的拦截逻辑代码;
  继续看这个plugin方法:
在这里插入图片描述
  发现是个接口,找出它的实现类:
在这里插入图片描述
  选择PaginationInterceptor继续分析,它是分页拦截器,执行分页功能。找到上面看到的plugin方法:
在这里插入图片描述
  plugin方法里面根据target类型进行返回,如果是StatementHandler类型的,就执行Plugin.wrap方法,其实这就是一个包装方法,输入两个对象,一个的被代理对象,一个是PaginationInterceptor自身。
  继续看这个wrap方法:
在这里插入图片描述
  典型的动态代理实现,调用的是Proxy.newProxyInstance方法来生成代理对象。

2.2 小结

  由于真正去执行ExecutorParameterHandlerResultSetHandlerStatementHandler类中的方法的对象是代理对象,所以在执行方法时,首先调用的是Plugin类(实现了InvocationHandler接口)的invoke方法,如下:

在这里插入图片描述
  可以关注下Interceptor接口的intercept方法实现,一般需要用户自定义实现逻辑,其中有一个重要参数,即Invocation类,通过改参数我们可以获取执行对象,执行方法,以及执行方法上的参数,从而进行各种业务逻辑实现,一般在该方法的最后一句代码都是invocation.proceed()(内部执行method.invoke方法),否则将无法执行下一个拦截器的intercept方法。
  以上逻辑对应的时序图如下,这里我们以执行executor对象的query方法为例,且假设有两个拦截器存在:
在这里插入图片描述

3、使用方法

3.1 注册插件

  注册插件的方法有两种:

  第一种:单纯使用Mybatis,在Mybatis的配置文件注册:

  第二种,和Spring整合的Mybatis,在Spring的配置文件中注册:

3.2 使用

  配置好了之后,Mybatis创建四大对象的时候会就会创建代理对象。实现相应的插件功能。

4、总结

  简单的说,mybatis插件就是对ParameterHandlerResultSetHandlerStatementHandlerExecutor这四个接口上的方法进行拦截,利用JDK动态代理机制,为这些接口的实现类创建代理对象,在执行方法时,先去执行代理对象的方法,从而执行自己编写的拦截逻辑,所以真正要用好mybatis插件,主要还是要熟悉这四个接口的方法以及这些方法上的参数的含义;

  另外,如果配置了多个拦截器的话,会出现层层代理的情况,即代理对象代理了另外一个代理对象,形成一个代理链条,执行的时候,也是层层执行;

转载地址:http://bzf.baihongyu.com/

你可能感兴趣的文章
mysql5.7示例数据库_Linux MySQL5.7多实例数据库配置
查看>>
Mysql8 数据库安装及主从配置 | Spring Cloud 2
查看>>
mysql8 配置文件配置group 问题 sql语句group不能使用报错解决 mysql8.X版本的my.cnf配置文件 my.cnf文件 能够使用的my.cnf配置文件
查看>>
MySQL8.0.29启动报错Different lower_case_table_names settings for server (‘0‘) and data dictionary (‘1‘)
查看>>
MYSQL8.0以上忘记root密码
查看>>
Mysql8.0以上重置初始密码的方法
查看>>
mysql8.0新特性-自增变量的持久化
查看>>
Mysql8.0注意url变更写法
查看>>
Mysql8.0的特性
查看>>
MySQL8修改密码报错ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
查看>>
MySQL8修改密码的方法
查看>>
Mysql8在Centos上安装后忘记root密码如何重新设置
查看>>
Mysql8在Windows上离线安装时忘记root密码
查看>>
MySQL8找不到my.ini配置文件以及报sql_mode=only_full_group_by解决方案
查看>>
mysql8的安装与卸载
查看>>
MySQL8,体验不一样的安装方式!
查看>>
MySQL: Host '127.0.0.1' is not allowed to connect to this MySQL server
查看>>
Mysql: 对换(替换)两条记录的同一个字段值
查看>>
mysql:Can‘t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock‘解决方法
查看>>
MYSQL:基础——3N范式的表结构设计
查看>>