摘自:https://www.cnblogs.com/qm-article/p/11785350.html

mybatis的插件机制

 

一、mybatis的插件介绍

关于mybatis的插件,我想大家也都用过,就比如最常用的逆向工程,根据表结构生成model,dao,xml文件,还有分页插件,那这些插件的工作原理是怎么样的呢,就比如分页插件,它为什么能改变我们在xml文件中写的sql语句,本文将带大家一起来了解mybatis的插件机制。(由于本人也是在不断学习,文中难免有错误或不足之处,还望指正,本文基于mybatis3.3.0版本),下面将围绕这几个方面

1、插件入口,即怎么把插件注入到mybatis代码里面

2、插件能拦截哪些类或哪些方法

3、举例简易分表插件原理

二、插件入口

在先了解前,我们来一段自定义mybatis插件的代码

  1. 1 import org.apache.ibatis.executor.statement.StatementHandler;
  2. 2 import org.apache.ibatis.plugin.*;
  3. 3
  4. 4 import java.sql.Connection;
  5. 5 import java.util.Properties;
  6. 6
  7. 7 @Intercepts(
  8. 8 value = {
  9. 9 @Signature(
  10. 10 type = StatementHandler.class,
  11. 11 method = "prepare",
  12. 12 args = {Connection.class} // 不同版本的prepare方法参数不一样,高版本的还有一个Integer参数
  13. 13 )
  14. 14 }
  15. 15 )
  16. 16 public class PluginDemo implements Interceptor {
  17. 17 @Override
  18. 18 public Object intercept(Invocation invocation) throws Throwable {
  19. 19 return invocation.proceed();
  20. 20 }
  21. 21
  22. 22 @Override
  23. 23 public Object plugin(Object target) {
  24. 24 return Plugin.wrap(target,this);
  25. 25 }
  26. 26
  27. 27 @Override
  28. 28 public void setProperties(Properties properties) {
  29. 29
  30. 30 }

要自定义mybatis插件,必须得实现Interceptor接口,这个接口有三个抽象方法

1、intercept,这个方法是mybatis的核心方法,要实现自定义逻辑,基本都是改造这个方法,其中invocation参数可以通过反射要获取原始方法和对应参数信息

2、plugin,它的作用是用来生成一个拦截对方,也就是代理对象,使得被代理的对象一定会经过intercept方法,通常都会使用mybatis提供的工具类Plugin来获取代理对象,如果有自己独特需求,可以自定义

3、setProperties,这个方法就是用来设置插件的一些属性

其中@intercepts注解就是用来标明拦截哪些类,哪些方法。

当我们脱离spring容器来使用mybatis的时候,我们通常是这样写代码的

而在mybatisConfig.xml文件中,我们有配置数据库连接信息,插件,别名,mapper文件映射地址等信息,(温馨提示,这些配置有一定顺序,如果不按照顺序配置,则mybatis解析时会抛出异常,详细配置信息可以参考mbatis的dtd文件配置)既然在配置文件中配置了,那肯定也会被解析掉,如下图,在XmlConfigBuild中进行解析

解析后,插件信息会被存储到configuation中InterceptorChain集合里面,这个configuation在mybatis运行周期是一个单例的,它负责存储所有的配置信息

最终,mybatis的插件信息完整的注入到了configuation里面。

二、mybaits插件能拦截哪些类或哪些方法

在正常开发流程中,我们基本都是通过先获取sqlSession,如果不采用自定义配置,在默认的sqlsession实现就是defaultSqlSession,在该类的一个方法里就隐含了融合插件,

其中会获取到executor,这个类是通过configuation获取的,

最终融合插件的方法就是图中红框的代码。它会为原始的executor类生成代理类。从而你在执行executor类的一些方法时,比如query,update方法,会先生成对应的代理对象,myabtis采用的是jdk的动态代理,代理后,你执行executor类的query,update方法时会自动转接到你自定义的插件intercept方法里面,也可以理解为覆盖原来的方法。

通过这,我们大概也可以猜测的出,mybatis插件要拦截的类,很大原因在configuation类中有生成,也不带大家绕弯子了,来看截图

拦截statementHandler接口的实现类,它通过routingStatementHandler来实现路由,最终定向到prepareStatementHandler类

拦截parameterHandler。这个接口是用来封装参数用的,也就是最终将参数设置到sql里面

拦截ResultSetHandler接口,它主要用于处理sql运行返回的结果

总结,mybatis可以拦截的类分四大类

一、executor,executor类可以说是执行sql的全过程,如组装参数,sql改造,结果处理,比较广泛,但实际用的不多

二、StatementHandler,这个是执行sql的过程,可以获取到待执行的sql,可用来改造sql,如分页,分表,最常拦截的类

三、paremeterHandler,这个用来拦截sql的参数,可以自定义参数组装规则

四、resultHandler,这个用来处理结果

三、简易版分表插件

  1. 1 import org.apache.ibatis.executor.statement.StatementHandler;
  2. 2 import org.apache.ibatis.mapping.BoundSql;
  3. 3 import org.apache.ibatis.plugin.*;
  4. 4 import org.apache.ibatis.reflection.MetaObject;
  5. 5 import org.apache.ibatis.reflection.SystemMetaObject;
  6. 6
  7. 7 import java.sql.Connection;
  8. 8 import java.util.Properties;
  9. 9
  10. 10 @Intercepts(
  11. 11 value = {
  12. 12 @Signature(
  13. 13 type = StatementHandler.class,
  14. 14 method = "prepare",
  15. 15 args = {Connection.class}
  16. 16 )
  17. 17 }
  18. 18 )
  19. 19 public class PluginDemo implements Interceptor {
  20. 20 @Override
  21. 21 public Object intercept(Invocation invocation) throws Throwable {
  22. 22
  23. 23 /**
  24. 24 * 获取被拦截的目前类,在这里是拦截了statementHandler,所有目前类也就是它
  25. 25 * 通过这个类我们可以拿到待执行的sql语句,通常使用mataObject工具类来获取
  26. 26 * 关于这个工具类,大家可自行了解,个人认为这个工具类很强大
  27. 27 */
  28. 28 StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
  29. 29 MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
  30. 30 /**
  31. 31 * 先解释下为什么写成delegate.boundSql就可以拿到boundSql类
  32. 32 * 从前面也可以得知,statementHandler的默认实现是routingStatementHandler。
  33. 33 * 这个类有一个属性statementHandler,属性名就叫delegate,而这个属性的默认实现又是preparedStatementHandler
  34. 34 * 后面这个类又有属性boundSql,所以,最终形成的写法就是delegate.boundSql。
  35. 35 * 所以这也体现了MetaObject工具类的强大,可以通过实例传参,就可以根据属性名获取对应属性值
  36. 36 */
  37. 37 BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
  38. 38
  39. 39 // 待执行的sql,在这里也就是预编译后的sql,即参数位都是?号
  40. 40 String sql = boundSql.getSql();
  41. 41 /**
  42. 42 * 既然拿到了预编译后的sql,那就可以按照你自己的想法为所欲为,如分页,按年分表等等
  43. 43 * 分表的话,个人推荐druid的sql解析器,我认为还是不错的,大家可以自行了解
  44. 44 * 最后改造完sql,别忘了把它设置回去
  45. 45 * metaObject.setValue("delegate.boundSql.sql",sql);
  46. 46 * invocation.proceed,即原始方法的执行
  47. 47 * 注意点就是,因为mybatis插件采用的是代理模式,所以如果存在多个插件,会形成多个代理
  48. 48 * 你如果要拿到最原始的对象,还得进一步进行分解
  49. 49 * 如:while(metaObject.getValue(""h) != null){
  50. 50 * Object obj = metaObject.getValue("h");
  51. 51 * ....
  52. 52 * }
  53. 53 */
  54. 54 return invocation.proceed();
  55. 55 }
  56. 56
  57. 57 @Override
  58. 58 public Object plugin(Object target) {
  59. 59 return Plugin.wrap(target,this);
  60. 60 }
  61. 61
  62. 62 @Override
  63. 63 public void setProperties(Properties properties) {
  64. 64
  65. 65 }
  66. 66 }

-----------------------------------------------------------------------------------------------------------------------------分界线-------------------------------------------------------------------------------------

以上就是全部内容

一、mybatis的插件介绍的更多相关文章

  1. mybatis的插件机制

    一.mybatis的插件介绍 关于mybatis的插件,我想大家也都用过,就比如最常用的逆向工程,根据表结构生成model,dao,xml文件,还有分页插件,那这些插件的工作原理是怎么样的呢,就比如分 ...

  2. SSM 使用 mybatis 分页插件 pagehepler 实现分页

    使用分页插件的原因,简化了sql代码的写法,实现较好的物理分页,比写一段完整的分页sql代码,也能减少了误差性. Mybatis分页插件 demo 项目地址:https://gitee.com/fre ...

  3. 使用Mybatis Generator插件自动生成映射文件(cmd无法进入文件,dns服务器对区域没有权威等问题)遇到问题

           使用Mybatis Genertor插件自动生MyBatis所需要的DAO接口,实体模型类,Mapping映射文件,将生成的代码赋值到项目工程中即可.     有命令行,Eclipse插 ...

  4. 详解Mybatis通用Mapper介绍与使用

    使用Mybatis的开发者,大多数都会遇到一个问题,就是要写大量的SQL在xml文件中,除了特殊的业务逻辑SQL之外,还有大量结构类似的增删改查SQL.而且,当数据库表结构改动时,对应的所有SQL以及 ...

  5. Mybatis学习---Mybatis分页插件 - PageHelper

    1. Mybatis分页插件 - PageHelper说明 如果你也在用Mybatis,建议尝试该分页插件,这个一定是最方便使用的分页插件. 该插件目前支持Oracle,Mysql,MariaDB,S ...

  6. 基于Mybatis分页插件PageHelper

    基于Mybatis分页插件PageHelper 1.分页插件使用 1.POM依赖 PageHelper的依赖如下.需要新的版本可以去maven上自行选择 <!-- PageHelper 插件分页 ...

  7. 【MyBatis】MyBatis分页插件PageHelper的使用

    好多天没写博客了,因为最近在实习,大部分时间在熟悉实习相关的东西,也没有怎么学习新的东西,这周末学习了MyBatis的一个分页插件PageHelper,虽然没有那么的强大(我在最后会说明它的缺点),但 ...

  8. MyBatis学习总结(17)——Mybatis分页插件PageHelper

    如果你也在用Mybatis,建议尝试该分页插件,这一定是最方便使用的分页插件. 分页插件支持任何复杂的单表.多表分页,部分特殊情况请看重要提示. 想要使用分页插件?请看如何使用分页插件. 物理分页 该 ...

  9. Mybatis分页插件PageHelper的学习与使用

    目录 中文教程 PageHelper使用 后端程序员都知道,在Web系统中,分页是一种常见的功能,我之前写的分页方法都比较麻烦,移植性也不高,这就很不乐观了.作为一个积极开朗的程序员,怎么能不去了解P ...

随机推荐

  1. idea 新建maven项目时,避免每次都需要指定自己的maven目录

    01 .File->Other Settings -> Settings for New Project 02. 将Maven home directory目录修改成我们自己安装Maven ...

  2. Springboot提示数据库连接问题Connection is not available

    2019-05-29 11:19:51.824 WARN 854 --- [io-8080-exec-10] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL ...

  3. Codeforces 1190A. Tokitsukaze and Discard Items

    传送门 显然从左到右考虑每个要删除的数 维护一个 $cnt$ 表示之前已经删除了 $cnt$ 个数,那么当前所有要删除数的实际位置就要减去 $cnt$ 直接暴力枚举哪些数在最左边一个块然后一起删除 每 ...

  4. JSTL标签+El表达式把list集合数据展示到 JSP页面

    JSP页面 <%@ page import="cn.itcast.domain.User" %><%@ page import="java.util.L ...

  5. O001、写在最前面

    参考https://www.cnblogs.com/CloudMan6/p/5224114.html   <每天5分钟玩转 OpenStack>       1.系统讲解 OpenStac ...

  6. Python新式类与经典类(旧式类)的区别

    看写poc的时候看到的,思考了半天,现在解决了 转载自http://blog.csdn.net/zimou5581/article/details/53053775 Python中类分两种:旧式类和新 ...

  7. 使用sublimeserver启动本地服务器进行调试

    最近在做前后端分离的项目,访问后台接口的时候会产生跨域问题,修改了相关配置解决了跨域问题,但是配置中只对开发环境进行了设置,没有设置生产环境,为了验证生产环境确实无法访问后台接口遂npm run bu ...

  8. mysql的导入导出操作

    mysqldump工具基本用法 此方法不适用于大数据备份 备份所有数据库 mysqldump -u root -p --all-databases > all_database_sql 备份my ...

  9. layer单选框 radio的问题总结

    放官方文档: 位置 页面元素-表单:内置模块-表单属性title可自定义文本属性disabled开启禁用设置value="xxx"可自定义值,否则选中时返回的就是默认的onradi ...

  10. vim 搜索 向前,向后

    vim 搜索可以是 / 或者 ?,前者是往下找,后者是往前找. 用 n 查找下一个的时候,就和这两个指令指定的方向相同.如果你想改变方向的话,比如想往下找,那么 / 完了直接回车就行了.表示再次使用上 ...