Mybatis 的拦截器(Plugins)是一个非常有用的一个特性,可以在 Mybatis 操作数据库的生命周期中添加自定义的一些逻辑,非常适合用于做一些数据操作的记录、数据脱敏等功能
Mybatis 的生命周期
Mybatis 中 Executor、ParameterHandler、StatementHandler、ResultSetHandler 是 SQL 执行生命周期的四个关键节点,分别对应 Mybatis 中的四个接口。
拦截器
Interceptor 是 Mybatis 提供的一个拦截器接口,定义了三个方法,通过 intercept 方法对 Mybatis 生命周期中的节点进行拦截,并返回结果。
1 2 3 4 5 6 7 8 9 10 11 12
| public interface Interceptor { Object intercept(Invocation invocation) throws Throwable;
default Object plugin(Object target) { return Plugin.wrap(target, this); }
default void setProperties(Properties properties) { } }
|
拦截器注解
上述接口需要结合@Intercepts,@Signature 两个注解来完成对方法的拦截
1 2 3 4 5 6
| @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface Intercepts { Signature[] value(); }
|
1 2 3 4 5 6 7 8 9 10
| @Documented @Retention(RetentionPolicy.RUNTIME) @Target({}) public @interface Signature { Class<?> type();
String method();
Class<?>[] args(); }
|
@Signature 注解用于指定拦截的方法,包括拦截的类、方法、参数。
三个参数就是 Executor、ParameterHandler、StatementHandler、ResultSetHandler 接口中对应类型、方法名以及参数类型
type: 拦截的类
method: 拦截的方法
args: 拦截的参数类型
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
public interface StatementHandler { Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException;
void parameterize(Statement statement) throws SQLException;
void batch(Statement statement) throws SQLException;
int update(Statement statement) throws SQLException;
<E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException;
<E> Cursor<E> queryCursor(Statement statement) throws SQLException;
BoundSql getBoundSql();
ParameterHandler getParameterHandler(); }
@Intercepts({ @Signature( type = StatementHandler.class, method = "prepare", args = {java.sql.Connection.class, java.lang.Integer.class} ), @Signature( type = StatementHandler.class, method = "getBoundSql", args = {} ) })
|
拦截器方法
1 2 3 4 5 6 7 8 9 10 11 12
| public interface Interceptor { Object intercept(Invocation invocation) throws Throwable;
default Object plugin(Object target) { return Plugin.wrap(target, this); }
default void setProperties(Properties properties) { } }
|
intercept
intercept 是拦截器的核心方法,proceed 方法会调用被拦截的方法,返回结果会作为 intercept 方法的返回值。
Invocation 参数内部三个参数,target: 被拦截的对象, method: 被拦截的方法, args: 方法的参数
一个核心的方法 proceed() 调用被拦截的方法
plugin
plugin 方法用于为目标对象创建代理对象,决定是否需要对目标对象进行拦截处理。
setProperties
setProperties 方法用于接收配置文件中设置的属性参数,实现拦截器的可配置化。