最近在做新项目,基于若依(前后端分离版本)做的,他也使用了常用的分页插件PageHelper

老规矩,今天文章还是分三步走,先上文章导读,然后讲原理,最后讲解源码案例

最后达到的效果就是希望读者朋友们在看完我写的这篇文章后,能够秒懂别人写的MyBatis插件并且能够开发出自己的MyBatis的插件

文章导读

MyBatis 插件原理与实战

什么是插件?

插件就是在具体的执行流程插一脚(触发点、拦截器)来实现具体的功能。

一般插件会对执行流程中的上下文有依赖,抽象的说,我们也可以把MyBatis看作是JDBC的插件,只是功能越来来多,越来越强大,最后我们给了他一个新名字,叫做框架

不管怎样,JDBC的那一套还是不会变的,只是做了抽象、封装、归类等。

要想知道插件的原理,首先就要对它的执行流程有一定的把控。

执行流程

前边我们讲到,MyBatis是对JDBC的抽象、封装。

我们首先来回顾一下JDBC的执行流程。

JDBC执行流程

  1. 注册驱动;
  2. 获取Connection连接;
  3. 执行预编译;
  4. 执行SQL;
  5. 封装结果集;
  6. 释放资源;

给段伪代码通透理解下:

// 注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 获取链接
Connection con = DriverManager.getConnection(url, username, password);
// 执行预编译
Statement stmt = con.createStatement();
// 执行SQL
ResultSet rs = stmt.executeQuery("SELECT * FROM ...");
// 封装结果
while (rs.next()) {String name = rs.getString("name");String pass = rs.getString(1); // 此方法比较高效
}
// 释放资源
if (rs != null) {  // 关闭记录集}
if (stmt != null) {  // 关闭声明}
if (conn != null) { // 关闭连接对象}

上边的代码是不是很熟悉,我相信每个入门写Java代码的人,都写过这段代码。

紧接着,我们继续来了解MyBatis的执行流程。

MyBatis执行流程

  1. 读取MyBatis的核心配置文件;
  2. 加载映射文件;
  3. 构造会话工厂获取SqlSessionFactory;
  4. 创建会话对象SqlSession;
  5. Executor执行器;
  6. MappedStatement对象;
  7. 输入参数映射;
  8. 封装结果集;

上边的文字可能不太好理解,我这里也画一幅执行流程图,来方便理解。

有没有觉得MyBatis的执行流程和JDBC的执行流程主干也差不多,只是在主干过程中,把一些配置(mybatis-config.xml)、常用的定义文件单独抽离出来(mapper.xml)和一些附带扩展性的拦截点抽离了出来。

下面着重讲一讲我们的拦截点,因为插件就是基于我们的拦截点来做的扩展。

拦截点

结合上边的MyBatis执行流程,看下图的各个拦截点:

MyBatis拦截点

文字描述,MyBatis允许使用插件来拦截的方法调用包括:

  1. Executor:

    拦截执行器的方法 (update, query, flushStatements, commit, rollback,getTransaction, close, isClosed),Mybatis的内部执行器,它负责调用StatementHandler操作数据库,并把结果集通过 ResultSetHandler进行自动映射,另外,他还处理了二级缓存的操作。从这里可以看出,我们也是可以通过插件来实现自定义的二级缓存的;

  2. ParameterHandler:

    拦截参数的处理 (getParameterObject, setParameters) ,Mybatis直接和数据库执行sql脚本的对象。另外它也实现了Mybatis的一级缓存。这里,我们可以使用插件来实现对一级缓存的操作(禁用等等);

  3. ResultSetHandler:

    拦截结果集的处理 (handleResultSets, handleOutputParameters) ,Mybatis实现Sql入参设置的对象。插件可以改变我们Sql的参数默认设置;

  4. StatementHandler:

    拦截Sql语法构建的处理 (prepare, parameterize, batch, update, query) ,Mybatis把ResultSet集合映射成POJO的接口对象。我们可以定义插件对Mybatis的结果集自动映射进行修改。

拦截器为什么能够拦截

org.apache.ibatis.session.Configuration是在MyBatis初始化配置的类。

其中的newParameterHandlernewResultSetHandlernewStatementHandlernewExecutor这几个方法在创建指定的对象(newParameterHandler创建ParameterHandler、newResultSetHandler创建ResultSetHandler、newStatementHandler创建StatementHandler、newExecutor创建Executor)对象的时候,都会调用一个统一的方法:

创建对象

这4个方法实例化了对应的对象之后,都会调用interceptorChain的pluginAll方法,那么下面我们在来看pluginAll干了什么。

包路径:org.apache.ibatis.plugin.InterceptorChain

public Object pluginAll(Object target) {Interceptor interceptor;for(Iterator var2 = this.interceptors.iterator(); var2.hasNext(); target = interceptor.plugin(target)) {interceptor = (Interceptor)var2.next();}return target;}

原来这个pluginAll方法就是遍历所有的拦截器,然后顺序执行我们插件的plugin方法,一层一层返回我们原对象(Executor/ParameterHandler/ResultSetHander/StatementHandler)的代理对象。当我们调用四大接口对象的方法时候,实际上是调用代理对象的响应方法,代理对象又会调用四大接口对象的实例。

这里我们看到所有的拦截器Interceptor,其实它和我们平常写代码一样,也是多态的利用,存在一个拦截器Interceptor接口,我们在实现插件的时候,也实现这个接口,就会被调用。

Interceptor接口

包路径:org.apache.ibatis.plugin

public interface Interceptor {Object intercept(Invocation var1) throws Throwable;default Object plugin(Object target) {return Plugin.wrap(target, this);}default void setProperties(Properties properties) {}
}

这个接口只声明了三个方法:

  1. setProperties方法是在Mybatis进行配置插件的时候可以配置自定义相关属性,即:接口实现对象的参数配置;
  2. plugin方法是插件用于封装目标对象的,通过该方法我们可以返回目标对象本身,也可以返回一个它的代理,可以决定是否要进行拦截进而决定要返回一个什么样的目标对象,官方提供了示例:return Plugin.wrap(target, this);
  3. intercept方法就是要进行拦截的时候要执行的方法;

编写简单的MyBatis插件

注:MyBatis默认没有一个拦截器接口的实现类,开发者可以实现符合自己需求的拦截器

@Intercepts({@Signature(type= Executor.class, method = "update", args = {MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {public Object intercept(Invocation invocation) throws Throwable {return invocation.proceed();}public Object plugin(Object target) {return Plugin.wrap(target, this);}public void setProperties(Properties properties) {}
}

全局xml配置(实例化bean)

<plugins>
<plugin interceptor="org.format.mybatis.cache.interceptor.ExamplePlugin"></plugin>
</plugins>

这个拦截器拦截Executor接口的update方法(其实也就是SqlSession的新增,删除,修改操作),所有执行executor的update方法都会被该拦截器拦截到,就在里边做相对应的逻辑处理就可以了。

总结

今天这篇文章到这里结束了,讲解了什么是插件首先需要了解执行流程,然后回顾我们的JDBC流程来推导出MyBatis的执行流程,通过初始化的org.apache.ibatis.session.Configuration为切入点,跟踪到interceptorChain的pluginAll方法;最后通过一个简单的插件来实操了一波。

参考链接:

https://zhuanlan.zhihu.com/p/150008843

https://blog.csdn.net/weixin_44046437/article/details/100523028

https://blog.csdn.net/weixin_44046437/article/details/100526643

MyBatis 插件原理与实战相关推荐

  1. mybatis 插件原理

    [传送门]:mybatis 插件原理 转载于:https://www.cnblogs.com/virgosnail/p/10079838.html

  2. MyBatis(四)MyBatis插件原理

    MyBatis插件原理 MyBatis对开发者非常友好,它通过提供插件机制,让我们可以根据自己的需要去增强MyBatis的功能.其底层是使用了代理模式+责任链模式 MyBatis官方https://m ...

  3. 后端技术:mybatis插件原理详解

    关注"Java后端技术全栈" 回复"面试"获取全套面试资料 上次发文说到了如何集成分页插件MyBatis插件原理分析,看完感觉自己better了,今天我们接着来 ...

  4. MyBatis 插件原理与自定义插件-猜想

    MyBatis 的插件可以在不修改原来的代码的情况下,通过拦截的方式,改变四大核心对象的行为,比如处理参数,处理SQL,处理结果. 第一个问题: 不修改对象的代码,怎么对对象的行为进行修改,比如说在原 ...

  5. MyBatis插件原理解析及自定义插件实践

    一.插件原理解析 首先,要搞清楚插件的作用.不管是我们自定义插件,还是用其他人开发好的第三方插件,插件都是对MyBatis的四大核心组件:Executor,StatementHandler,Param ...

  6. MyBatis 插件原理与自定义插件

    MyBatis 通过提供插件机制,让我们可以根据自己的需要去增强MyBatis 的功能. 需要注意的是,如果没有完全理解MyBatis 的运行原理和插件的工作方式,最好不要使用插件,因为它会改变系底层 ...

  7. MyBatis 插件原理与自定义插件-插件编写与注册

    (基于spring-mybatis)运行自定义的插件,需要3 步,我们以PageHelper 为 1.编写自己的插件类 1)实现Interceptor 接口 这个是所有的插件必须实现的接口. 2)添加 ...

  8. MyBatis 插件原理与自定义插件-用代理模式我们就要解决几个问题

    1) 有哪些对象允许被代理?有哪些方法可以被拦截? 我们应该了解MyBatis 允许哪些对象的哪些方法允许被拦截,并不是每一个运行的节点都是可以被修改的.只有清楚了这些对象的方法的作用,当我们自己编写 ...

  9. 《MyBatis技术原理与实战》之SqlSession的用途

    1.Mybatis中SqlSession主要有两种用途: 获取映射器,让映射器通过命名空间和方法名称找到对应的SQL,发送给数据库执行后返回结果 直接通过命名信息去执行SQL返回结果,这是IBatis ...

  10. 《MyBatis技术原理与实战》之动态SQL

    Mybatis有两种方式配置SQL 方式一:使用XML文件配置 方式二:在注解中配置SQL 通常,使用第一种方式,这里也只阐述第一种方式中SQL的用法 Mybatis动态的SQL常用的几个元素 元素 ...

最新文章

  1. vs2015编译android,VS2015 Update2 构建 Android 程序问题汇总
  2. linkedin databus介绍——监听数据库变化,有新数据到来时通知其他消费者app,新数据存在内存里,多份快照...
  3. Javascript自定义事件功能与用法实例分析
  4. python爬取换页_一个可识别翻页的简易Python爬虫程序
  5. KClient——kafka消息中间件源码解读
  6. SQLite学习手册(数据库和事务)
  7. Icon class生成器(Python)
  8. 异常-throws的方式处理异常
  9. html vw自动跳到ie,CSS3动画/关键帧,在IE11问题中使用vw进行转换
  10. 基于matlab的回波,基于MATLAB回波信号产生与消除.doc
  11. android webview 图表,Android WebView 无法正常显示网页图表
  12. 公司应该如果管理员工?
  13. c语言中栈的作用,栈(Stack)的概念和应用及C语言实现
  14. 2008年日历带农历_头条文章--Excel中带农历的万年历设计方法一
  15. 智能工厂ERP解决方案
  16. unbuntu samba共享文件夹
  17. 4412——Linux驱动入门01
  18. python父亲节礼物_父亲节有什么礼物可以推荐?
  19. 解决“你没有权限访问,请与网络管理员联系”
  20. sublime text 3 插件 OmniMarkupPreviewer 报404解决办法

热门文章

  1. JAVA智能分析的简单聚众筹平台计算机毕业设计Mybatis+系统+数据库+调试部署
  2. 微信小程序微信授权登录
  3. SpringBoot---Tomcat日志配置
  4. journalctl工具基础介绍
  5. 基于支付场景下的微服务改造与性能优化
  6. linux hdparm 测试磁盘io,Linux测试硬盘读写速度之hdparm命令
  7. LogViewer_2
  8. 后渗透攻击阶段 PTES
  9. 红米note5linux刷机包__最新最全的红米Note5ROM刷机包下载、刷机教程_红米Note5论坛_移动叔叔...
  10. 软件配置--ubuntu16.04