一、什么是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()
就行了,其实 plugin
和 setProperties
不实现也没关系,因为 Interceptor
接口里有默认实现
其实只要实现 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();
}
}
类上面的注解,代表会拦截 Executor
的 query
方法,参数是这四个 query
方法 MappedStatement
, Object
, RowBounds
, ResultHandler
,也就是这个
然后就要把这个拦截器加到拦截器链里去,我这边用的 SpringBoot,所以是这么配置的
@Configuration
public class MybatisConfig {
@Bean
public Interceptor[] interceptors() {
ExecutorInterceptor executorInterceptor = new ExecutorInterceptor();
return new Interceptor[]{executorInterceptor};
}
}
三、源码解析
我们先看看四大对象(Executor
、StatementHandler
、ParameterHandler
、ResultSetHandler
)在创建的时候,干了什么事,创建的方法都在 Configuration
类里
我们发现,都有
interceptorChain.pluginAll
这个方法,都是传入什么对象,返回还是什么对象。
我们看看这个方法
可以看到 InterceptorChain
里有一个拦截器集合,pluginAll
方法就是遍历这个集合,并调用每个拦截器的 plugin
方法,而这个 plugin
方法就是接口 Interceptor
的默认方法
最终调用的是 Plugin
的 wrap
方法,我们再进去看下
可以看到这里是创建了代理类,而这个 Plugin
实现的正是 Java 动态代理机制的核心接口 InvocationHandler
,这里很显然了,当调用被拦截的方法时,会先调用 Plugin
类的 invoke
方法,看下这个方法
可以看到最终是调用的拦截器的 intercept
方法,也就是我们自己实现的那段逻辑
四、总结
Mybatis 的插件其实就是采用责任链机制,通过 JDK 动态代理来实现的。
- 在项目启动阶段,如果发现四大对象(
Executor
、StatementHandler
、ParameterHandler
、ResultSetHandler
)的方法有被拦截,就返回代理对象,否则就返回对象本身。 - 在调用 sql 阶段,如果调用四大对象的方法时,发现是代理对象,就执行
Plugin
的invoke
方法(最终会执行拦截器的intercept
方法),否则就执行原方法。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/154475.html