[由零开始] 七、手写Mybatis插件

[由零开始]七、手写Mybatis插件

  • 手写Mybatis插件
    • Mybatis插件分析
      • MyBatis 允许拦截的方法:
    • Mybatis插件原理
      • 开始
      • 拦截
    • 手写Mybatis插件
      • 插件接口
      • 实现插件

手写Mybatis插件

一般情况下, 开源框架都会提供插件或者其他形式的扩展点
开发者也可以根据业务需要自己开发想要的插件 大大的增加了灵活性
由于插件与业务无关,业务也无发感知插件的存在,所以可以无感的植入插件,从而增强功能(AOP)
以Mybatis举例 Mybatis我们常用的插件就有分页、分表等插件

ps:「我刚开始接触分页的时候就不太理解他是这么做到的 由于业务需要
(n张表不相关的表、然后各种过滤筛选出的数据拼装然后分页的恶心功能)
我花了三个小时手写了一个和数据库无关(没有limit)的一个纯粹用来分页的小工具
(和拦截器无关 不能叫插件 完全因为业务需要 对性能没有任何好处 吐槽一下神级产品)」

Mybatis插件分析

总的来说 Mybatis对持久层的操作主要就是靠四大核心对象(Executor StatementHandler ParameterHandler ResultSetHandler), 只看名字我们就知道都是干什么的了 毕竟我们前几章的时候这些名字都用到过,
实际上 对于Mybatis来说 插件就是一个拦截器 对Mybatis这四大核心对象的拦截, 用来增强底层的功能, 本质上是借助于底层的动态代理实现的, 换句话说 这四大对象都是代理对象

[由零开始] 七、手写Mybatis插件_第1张图片

MyBatis 允许拦截的方法:

执行器 Executor(update、query、commit、rollback )
SQL语法构建器 StatementHandler(prepare、parameterize、batch、update、query )
参数处理器 ParameterHandler(getParameterObject、setParameters )
结果集处理器 ResultSetHandlerhandle(ResultSets、handleOutputParameters)

Mybatis插件原理

开始

四大对象在开始创建的时候 每个创建出的对象都不是直接返回的 而是通过interceptorChain.pluginAll(parameterHandler);

获取到所有的Interceptor(拦截器 插件需要实现的接口) 然后调用interceptor.plugin(target);返回target包装后的对象

我们可以使用插件为目标对象创建一个代理对象; AOP(面向切面)我们的插件为四大对象创建出代理对象,代理对象就可以对四大对象的每个操作进行拦截.

拦截

  
@Intercepts({ //注意看这个大花括号,这里可以定义多个@Signature方法进行拦截
@Signature(type = StatementHandler.class,//这里指哪个接口
method = "prepare",//这里指接口内的方法名
args = { Connection.class, Integer.class}),
//这是拦截的方法入参, 如果方法重载是要通过方法名和入参来确定唯一的
})
public class MyPlugin implements Interceptor {

我们需要先把插件配置在sqlMapConfig.xml中 这样可以保证在启动时可以加载插件并保存插件实例到相关对象(InterceptorChain, 拦截器链)中

 <!--例子-->
<plugins>
<plugin interceptor="com.mybatis.plugin.ExamplePlugin"> </plugin>
</plugins>

配置好之后 在我们执行插件的时候 被拦截的实例也会被创建 创建完毕后
Mybatis会通过JDK动态代理为实例生成代理类
然后插件下的逻辑就可以在 要执行的方法被调用前执行.

手写Mybatis插件

插件接口

Mybatis插件接口- Interceptor
1、Interceptor方法, 插件的核心方法
2、plugin方法, 生成target的代理对象
3、setProperties方法, 传递插件所需参数

实现插件

这是我自己的定义的MrSoonPlugin

首先第一点 我们要配置好xml
第二点 我们的MrSoonPlugin是实现的 Interceptor
MrSoonPlugin implements Interceptor
明白了这两点 我们真正产生影响的就是
System.out.println(“对方法进行了增强。。。”);
这里 如果我们想要做一些更难的执行也只是需要改这里就OK


@Intercepts({@Signature(type= StatementHandler.class,
        method = "prepare",
        args = {Connection.class,Integer.class}
                        )
})
public class MrSoonPlugin implements Interceptor {


    /**
     * 拦截方法 只要被拦截的目标对象的目标方法被执行时,每次都会执行intercept方法
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("对方法进行了增强。。。");
        return invocation.proceed();//原方法执行
    }


    /**
     * 主要为了 把当前的拦截器生成代理 存在拦截器链中
     * @param target 要拦截的对象
     * @return 代理对象
     */
    @Override
    public Object plugin(Object target) {
        Object wrap = Plugin.wrap(target, this);
        return wrap;
    }


    /**
     * 主要是为了获取配置文件参数
     * @param properties
     */
    @Override
    public void setProperties(Properties properties) {
        System.out.println("获取到的配置文件的参数是:"+properties);
        }
}

剩下就可以打上debug 走一下源码
我们对这块的理解也就清楚了

你可能感兴趣的:(由零开始)