Mybatis插件原理

35 篇文章 1 订阅
4 篇文章 0 订阅
Mybatis插件允许开发者拦截核心接口调用,如Executor,实现功能增强。自定义插件需实现Interceptor接口并使用@Intercepts注解指定拦截目标。在调用方法时,通过JDK动态代理的InvocationHandler实现拦截器逻辑,形成责任链模式。在项目启动时,被拦截的对象会被代理,执行时调用intercept方法。
摘要由CSDN通过智能技术生成

一、什么是Mybatis插件

MyBatis 插件是 MyBatis 提供的一种机制,它可以在 MyBatis 内部的一些核心接口上拦截方法调用,从而实现对 MyBatis 核心功能的增强和扩展。
拦截器可以 对MyBatis 中的执行器(Executor)、语句处理器(StatementHandler)、参数处理器(ParameterHandler)和结果集处理器(ResultSetHandler)进行拦截,从而实现在执行SQL语句前后、分页、加密解密和打印日志等功能的实现。

二、自定义插件

首先自定义插件要实现 Mybatis 的 Interceptor 接口,然后实现这个接口的3个方法,最后在类上打上 @Intercepts 注解,并用 @Signature 注解标注要拦截的接口名称、方法名称以及参数列表。我们用 Executor 来举例

@Intercepts(
        {@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
@Slf4j
public class ExecutorInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //增加自己的逻辑
        log.info("执行器-------自定义处理逻辑");
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}

plugin 方法统一都是这么写,setProperties 方法空着没关系,重点是 intercept 方法,增加自己的逻辑,最后调用 invocation.proceed() 就行了,其实 pluginsetProperties 不实现也没关系,因为 Interceptor 接口里有默认实现
图片.png
其实只要实现 intercept 方法就可以了,像这样

@Intercepts(
        {@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
@Slf4j
public class ExecutorInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //增加自己的逻辑
        log.info("执行器-------自定义处理逻辑");
        return invocation.proceed();
    }

}

类上面的注解,代表会拦截 Executorquery 方法,参数是这四个 query 方法 MappedStatement, Object, RowBounds, ResultHandler,也就是这个
图片.png然后就要把这个拦截器加到拦截器链里去,我这边用的 SpringBoot,所以是这么配置的

@Configuration
public class MybatisConfig {

    @Bean
    public Interceptor[] interceptors() {
        ExecutorInterceptor executorInterceptor = new ExecutorInterceptor();
        return new Interceptor[]{executorInterceptor};
    }
}

三、源码解析

我们先看看四大对象(ExecutorStatementHandlerParameterHandlerResultSetHandler)在创建的时候,干了什么事,创建的方法都在 Configuration 类里
图片.png
图片.png我们发现,都有 interceptorChain.pluginAll 这个方法,都是传入什么对象,返回还是什么对象。
我们看看这个方法
图片.png
可以看到 InterceptorChain 里有一个拦截器集合,pluginAll 方法就是遍历这个集合,并调用每个拦截器的 plugin 方法,而这个 plugin 方法就是接口 Interceptor 的默认方法
图片.png
最终调用的是 Pluginwrap 方法,我们再进去看下
图片.png
可以看到这里是创建了代理类,而这个 Plugin 实现的正是 Java 动态代理机制的核心接口 InvocationHandler,这里很显然了,当调用被拦截的方法时,会先调用 Plugin 类的 invoke 方法,看下这个方法
图片.png
可以看到最终是调用的拦截器的 intercept 方法,也就是我们自己实现的那段逻辑

四、总结

Mybatis 的插件其实就是采用责任链机制,通过 JDK 动态代理来实现的。

  1. 在项目启动阶段,如果发现四大对象(ExecutorStatementHandlerParameterHandlerResultSetHandler)的方法有被拦截,就返回代理对象,否则就返回对象本身。
  2. 在调用 sql 阶段,如果调用四大对象的方法时,发现是代理对象,就执行 Plugininvoke 方法(最终会执行拦截器的 intercept 方法),否则就执行原方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

每天进步亿点点的小码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值