Mybatis插件原理

得意时要看淡,失意时要看开。不论得意失意,切莫大意;不论成功失败,切莫止步。志得意满时,需要的是淡然,给自己留一条退路;失意落魄时,需要的是泰然,给自己觅一条出路Mybatis插件原理,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

一、什么是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 方法),否则就执行原方法。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/154475.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!