在Mybatis中,有一个强大的机制可以让我们快速地侵入到Mybatis的底层操作,从而去扩展Mybatis的功能,这就是插件机制,我们也可以叫作Mybatis的拦截器机制。

一.基本原理

在Mybatis架构体系中,有着四大组件(对象),分别是Executor,StatementHandler,ParameterHandler,ResultSetHandler。而我们在阅读Mybatis的底层源码的时候,可以很容易地发现在Mybatis中对这四大组件进行创建的时候都调用了一个interceptor.plugin的方法。所以说我们的插件针对的只能是这四大对象。顾名思义,interceptor中文就是拦截器的意思,说到拦截器我们很容易地就想到了它的功能就是在某个方法在被执行之前或被执行之后去增强这个方法的逻辑,这里其实就有点AOP(切面编程)的味道了。而对于Mybatis的插件机制来说,它的实现正是使用的jdk的动态代理机制实现的切面编程,为我们的四大对象都生成一个代理对象,从而去增强我们四大对象执行对应方法的逻辑。

二.插件基本使用

在这里简略地讲下我们的插件是怎么使用的。

运行结果:

这样这个Intercepor就配好了,并且在Executor执行query方法的时候会执行里面的intercept方法的逻辑。

三.插件底层原理的实现

为什么我们像上图这样配置就能够使我们的插件生成四大组件的代理对象从而能执行到里面的intercept方法的增强逻辑尼?而且可以发现打印的日志“拦截的目标类”都是打印出四大对象,下面我们一起来看源码来了解下。

首先我们这里随便看一下四大组件其中一个组件在创建后插件对其做了什么操作,这里就以Executor为例吧,进入到初始化Executor的方法。

Executor初始化的逻辑是在创建SqlSession的过程中创建的,所以我们来到创建SqlSession时里面的某一段源码中

对于Mybatis中SqlSession创建过程的解析,可以回去看:

Mybatis原理解析(二)SqlSession的创建过程

这里有执行了一句interceptorChain.pluginAll(executor)方法,仔细看这个方法,我们在创建出Executor对象的时候,把这个对象传进这个方法,然后就又返回了Executor对象给我们了,猜测里面应该是对这个对象进行了包装,我们可以再点进去这个方法看看

里面是拿到每一个Interceptor然后调用了interceptor的plugin方法,这个方法把我们的Executor对象拿到之后执行完就又返回给我们了,所以说这个方法就是对我们的四大对象进行包装的方法了,而前面我们也说过了,插件机制的实现核心在于对目标对象生成动态代理,所以说我们在实现自己的interceptor的时候,plugin方法里面我们就是要拿到目标类,对目标类生成动态代理对象然后返回了。

此时我们的目标很明确了,就是要在自定义的Interceptor的plugin方法里面对目标类生成动态代理并且返回,那么我们现在回到我们自定义的Interceptor的plugin方法中

可以看到里面应该是创建目标类的动态代理对象的,而这里直接调用了一个Plugin.wrap(target,this)方法,传入了目标类以及自身对象,那么我们进入这个方法看看,而直接看源码的话不太好理解,所以我们现在直接debug看看

在这里我们发现有一个getSignatureMap,首先我们从名字就感觉到有点熟悉对不对?signature这个单词好像哪里有写过,对,其实我们就在给我们的自定义Interceptor这个类上面写过这个注解,而这个方法会不会就是拿到我们在Interceptor中写的所有的@Signature注解的信息尼?我们深入看看这个方法

可以发现原来这个方法和我们的猜测一致,就是去解析我们的写的注解的信息的。接着我们再往下去看

发现我们拿到了目标类(这里的目标类就是四大对象)的类对象,然后把类对象和上面返回的map传入了一个getAllInterfaces方法中,看名字应该是拿接口类对象的,我们继续深入

 最终返回给我们的就是包含有四大对象的类对象的数组了,

而如果这个数组的长度不大于0的话,那么就说明这个目标对象不需要被拦截,直接返回这个目标对象,而如果大于0的话,说明这个目标对象需要被拦截处理,则用jdk的动态代理机制生成对应的代理对象。这样整个wrap方法就执行成功了。那么这里就总结下wrap方法:首先这个方法会解析我们在自定义Interceptor类上面的所有注解信息,以type属性值为key,以根据method,args属性值生成对应的type的Method对象组成的set集合为value,然后再去根据这个map去配对有没有以四大组件类对象为key的entry,如果有,就把目标对象实现的接口类对象(即四大组件之一)放到数组中,最后判断这个数组大小是否大于0,大于0的话说明此刻需要为目标对象创建一个动态代理对象,否则就直接返回这个目标对象即可。

在得到了目标对象的代理对象之后,之后执行的这个目标对象的所有方法都会先去执行代理对象的invoke方法了。而我们上面传入的实现了InvocationHandler接口的类就是Plugin类,我们进入这个类的invoke方法看看

可能看到这里你会有个疑问,就是如果当前执行的方法是我们指定要拦截的方法,然后就执行了return interceptor.intercept(new Invocation(target,method,args)),可以看到这是返回了自定义拦截器的intercept方法的返回值,那么我们知道动态代理中要对一个方法进行增强,那么增强之后还要去执行原来的代理的,即一定要返回method.invoke(target,args)的返回值才会执行原来的代码,那么我们上面最终直接返回intercept方法的返回值不就在增强之后执行不了原始方法的逻辑了吗?其实不然,我们的intercept方法最后返回的其实就是method.invoke(target,args)这句代码的返回值,因为我们在intercept方法中最终调用了invocation.proceed()这句代码,而这句代码里面,我们可以看看

其实这句代码里面还是method.invoke(target,args)这句代码,所以说我们在增强了方法之后还是会执行原始方法的逻辑的。

最后总结Mybatis的插件机制的原理:插件其实就是只针对四大对象有作用的,因为在Mybatis里面写死了在四大对象创建的过程中,都会把对象扔到插件当中去,从而生成对应的动态代理对象。而生成动态代理对象的方法也正是在插件的plugin方法中的去实现的,Mybatis对生成动态代理对象封装了一个Plugins类的wrap方法,这个方法原理是首先去拿到我们在自定义的Interceptor类上面的@Intercepts以及@Signature注解的信息去封装成一个以type属性值为key,以根据method,args属性值生成对应的type的Method对象组成的set集合为value的map对象,然后这个map里面尼就缓存了哪个类的哪个方法要被拦截增强处理,而在执行被代理对象的方法的时候就会进入到invoke方法中去,在invoke方法中去判断当前执行的方法是否是有在map中存在,如果存在就执行增强方法(intercept方法),如果不存在就执行原始方法的逻辑。所以插件的核心就是动态代理机制!

Mybatis插件机制原理相关推荐

  1. Atitit 插件机制原理与设计微内核 c# java 的实现attilax总结

    Atitit 插件机制原理与设计微内核 c# java 的实现attilax总结 1. 微内核与插件的优点1 2. 插件的注册与使用2 2.1. Ioc容器中注册插件2 2.2. 启动器微内核启动3 ...

  2. mybatis 插件机制

    mybatis 4大插件 分页插件功能设计 代码 <plugins><plugin interceptor="com.wfg.interceptor.PageInterce ...

  3. MyBatis 源码分析 - 插件机制

    1.简介 一般情况下,开源框架都会提供插件或其他形式的拓展点,供开发者自行拓展.这样的好处是显而易见的,一是增加了框架的灵活性.二是开发者可以结合实际需求,对框架进行拓展,使其能够更好的工作.以 My ...

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

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

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

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

  6. for循环执行 mybatis_MyBatis 插件机制详解

    MyBatis 是现在比较流行的 ORM 框架,得益于它简单易用,虽然增加了开发者的一些操作,但是带来了设计和使用上的灵活,得到广泛的使用.之前的一篇文章MyBatis 初始化之XML解析详解中我们已 ...

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

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

  8. MyBatis(四)MyBatis插件原理

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

  9. 深入剖析 mybatis 原理(四)插件的原理和应用

    < 一生所爱> 从前现在过去了再不来 红红落叶长埋尘土内 开始终结总是没变改 天边的你飘泊白云外 苦海翻起爱恨 在世间难逃避命运 相亲竟不可接近 或我应该相信是缘份 情人别后永远再不来(消 ...

  10. Android 插件化原理学习 —— Hook 机制之动态代理

    前言 为了实现 App 的快速迭代更新,基于 H5 Hybrid 的解决方案有很多,由于 webview 本身的性能问题,也随之出现了很多基于 JS 引擎实现的原生渲染的方案,例如 React Nat ...

最新文章

  1. visualize_object_model_3d算子说明
  2. Java8-Stream 概括
  3. 使用Phar来打包发布PHP程序
  4. OPENCV2.2移植说明
  5. 昆仑通态如何连接sqlserver数据库_sqlserver数据库怎么开启远程连接,给到别人访问...
  6. python随机画圆_python生成随机图形验证码详解
  7. GridView中使用DropDownList的OnSelectedIndexChanged事件
  8. win10安装wsl2和图形化界面
  9. 标学教育计算机等级考试系统,标学教育电脑版
  10. office2010安装需MSXML版本6.10.1129.0详解解决方案
  11. linux的php探针使用,php探针在Linux下的安装过程分享
  12. 黑马java idea (据说是完整的)网盘
  13. 私有化+国产化,这款安全可靠的知识管理系统超赞
  14. 黑猴子的家:Azkaban3.84.4之参考资料
  15. Python可视化--条形图
  16. (新)Chrome浏览器自定义背景插件
  17. 黑马头条项目-Vue-day9-文章详情模块、关注与取消关注,点赞和喜欢功能
  18. OSI七层模型及各层功能概述
  19. -XX:MaxDirectMemorySize直接内存无效问题
  20. 题目:什么是内联函数

热门文章

  1. 极客大学产品经理训练营 产品文档和原型 作业5
  2. next_permutation()
  3. Android studio3.5调用Numcpp库方法
  4. docker部署flask服务方法
  5. python后端和爬虫_【后端开发】python爬虫难学吗
  6. 浅谈算法和数据结构: 十一 哈希表
  7. 【Gym - 101848D】XOR【多个数异或的典型问题】【费马小定理】
  8. 特征值,特征向量,特征多项式
  9. mysql query profiler_Using the New MySQL Query Profiler
  10. 使用py 和flask 实现的服务器系统目录浏览,日志文件实时显示到网页的功能