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

    更新pip的命令  https://pip.pypa.io/

  2. idea 去除重复代码提醒

  3. redis 学习(10)-- redis 慢查询

    redis 慢查询 什么是慢查询 MySQL会记录下查询超过指定时间的语句,我们将超过指定时间的SQL语句查询称为慢查询,都记在慢查询日志里. redis 的生命周期 客户端向Redis服务器发送命令 ...

  4. Nginx负载均衡调度算法

    Nginx支持的负载均衡调度算法方式如下: 1. weight轮询(默认) 接收到的请求按照顺序逐一分配到不同的后端服务器,即使在使用过程中,某一台后端服务器宕机,nginx会自动将该服务器剔除出队列 ...

  5. php运行结果设置无缓存

    修改配置php.ini vim /usr/local/php/lib/php.ini opcache.enable= 重启php服务 service php-fpm restart done! 参考地 ...

  6. java实现spark常用算子之groupbykey

    import org.apache.spark.SparkConf;import org.apache.spark.api.java.JavaPairRDD;import org.apache.spa ...

  7. N1考试必备词汇

    相次ぐ あいつぐ 淡い あわい 合間 あいま 渋い しぶい 相俟つ あいまつ 慌てよう あわてよう 明るい あかるい 安易過ぎる 明らか あきらか 用心 ようじん 悪事 あくじ 案の定 あんのじょう ...

  8. BZOJ1791 基环树直径

    非递归版4S /************************************************************** Problem: 1791 User: 18357 Lan ...

  9. 关于客户端连接mysql的授权问题

    mysql远程连接 Host * is not allowed to connect to this MySQL server的错误. 是因为mysql需要授权才能访问.授权方式: 授权给某一个ip: ...

  10. HTTP与TCP的区别和联系(转)

    https://www.cnblogs.com/baizhanshi/p/8482612.html