本文采用知识共享 署名-相同方式共享 4.0 国际 许可协议进行许可。
访问 https://creativecommons.org/licenses/by-sa/4.0/ 查看该许可协议。
MyBatis 的插件基于拦截器思想,基于动态代理实现,我们可以对 MyBatis 中以下四大组件中的 method 进行拦截
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query)
3.1.7.1) 介绍:
我们可以通过实现 Interceptor 接口,实现和重写接口中的三个扩展方法:
- intercept(Invocation invocation):此接口为主扩展方法,invocation.proceed() 可以继续运行被拦截的方法,使我们可以在前后扩展。
- Object plugin(Object target):是的它就是上一节我们分析原理时执行的 plugin 函数,此函数是一个默认方法,可以重写它对创建代理时扩展。
- setProperties(Properties properties):在 SqlMapConfig.xml 中声明插件的 plugin 标签定义的参数,会传递到 properties 中。
3.1.7.2) 栗子:
定义:
@Intercepts({@Signature(
type = Executor.class, method = "update",
args = {MappedStatement.class, Object.class}
)})
public class ExampleInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
/* Before process */ Object result = invocation.proceed(); /* After process */
return result;
}
}
声明:
<plugins>
<plugin interceptor="cat.wars.ExampleInterceptor"></plugin>
</plugins>
3.1.7.3) 原理:
Configuration 中创建四大组件时都会调用 interceptorChain.pluginAll
方法来扩展,如 ParameterHandler
,从而返回一个重重代理对象
Configuratoin
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
// Create instance
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
// 将创建的 instance 交给 Interceptor Chain,执行完 pluginAll 后会返回一个重重(loop)代理对象
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
return parameterHandler; // 返回代理对象
}
InterceptorChain
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target); // 执行定义的 plugin 实现动态代理
}
return target;
}