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

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

被折叠的 条评论
为什么被折叠?



