【Mybatis】插件
参考:https://mybatis.org/mybatis-3/zh/configuration.html#plugins
使用方式
编写自己的插件类
@Intercepts({ @Signature(type = StatementHandler.class, method = "query", args = { Statement.class, ResultHandler.class}) })
public class SQLInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
……
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
……
}
}
- 实现Interceptor接口
- 添加@Intercepts({@Signature()}),指定拦截的对象和方法、方法参数
- 实现接口的3个方法:
// 用于覆盖被拦截对象的原有方法(在调用代理对象Plugin的invoke()方法时被调用)
Object intercept(Invocation invocation) throws Throwable;
// target 是被拦截对象,这个方法的作用是给被拦截对象生成一个代理对象,并返回它
Object plugin(Object target);
// 设置参数
void setProperties(Properties properties);
在mybatis配置文件中注册插件
<!-- 插件 -->
<plugins>
<plugin interceptor="com.gupaoedu.interceptor.SQLInterceptor">
<property name="gupao" value="betterme"/>
</plugin>
<plugin interceptor="com.gupaoedu.interceptor.MyPageInterceptor">
</plugin>
</plugins>
插件的执行顺序和定义顺序相反,如上定义,先执行MyPageInterceptor再执行SQLInterceptor
流程
原理
动态代理
允许代理(拦截)的对象和方法
代理(拦截)时机
- Executor: openSession()方法的时候,executor = (Executor) interceptorChain.pluginAll(executor);
- StatementHandler:doQuery方法的时候,statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
- ParameterHandler:doQuery方法的时候,parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
- ResultSetHandler:doQuery方法的时候,resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
代理(拦截)顺序
代理类(Plugin)
- return Plugin.wrap(target, this);返回代理对象
- 调用invoke()方法执行代理方法,其中会调用拦截器的intercept()方法
- 调用invocation的proceed()方法返回到被代理对象被拦截的地方
总结
责任链
- 插件的层层拦截(代理)
举例
PageHelper
应用场景
作业
- 在未启用日志组件的情况下,输出执行的完整SQL(先实现查询的拦截),并且统计SQL的执行时间
- 当我们传入RowBounds做翻页查询的时候,使用limit物理分页,代替原来的逻辑分页。
评论区