Mybatis插件通常意义就是自定义的拦截器,基于业务需求,需要在进行数据库查询之前或者之后进行拦截。如从线程变量中传递参数,动态修改SQL来实现数据的筛选,而不是每次在查询前,手动将条件注入到查询中;或者在不破坏原有查询逻辑时,动态的添加字段insert/update等;
类型有:
Executor、ParameterHandler、ResultSetHandler、StatementHandler
拦截器使用:
》@intercepts声明该类为拦截器,@signature声明拦截对象;
》method为我们需要拦截的prepare方法,type为所要拦截的接口类,args为prepare方法的参数;
》拦截器顺序
sqlSessionFactory.getConfiguration().InterceptorChain中的 pluginAll中遍历所有拦截器
通过调用拦截器的plugin()方法生成动态代理对象;
第一次循环的代理对象是原始的StatementHandler返回的是Plugin类型的代理类P1
第二次循环代理的对象是P1返回的是Plugin类型的代理类P2;
执行顺序并非1 > 2 >3,而是3 > 2 > 1
Interceptor3:{
Interceptor2: {
Interceptor1: {
target: Executor
}
}
}
举个栗子:
当需要根据当前用户的不同属性判别用户的数据权限,在不破坏原有数据查询逻辑的情况下,可通过拦截器实现数据权限过滤:
自定义EntitledQueryInterceptor 注入spring bean
@Intercepts(
{
@Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class}),
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
}
)
public class EntitledQueryInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
}
@Override
public Object plugin(Object target) {
return (target instanceof Executor) ? Plugin.wrap(target, this) : target;
}
@Override
public void setProperties(Properties properties) {
}
}
在实际使用时,配合PageHelper等插件可能会产生冲突问题,PageInterceptor是executor拦截器,如果sqlSessionFactory.getConfiguration().InterceptorChain后加入了PageInterceptor,那么运行时就先执行PageInterceptor,此时如果自定义的拦截器添加了新参数在SQL中,就会出现参数NotFound error。
org.apache.ibatis.binding.BindingException: Parameter '*' not found. Available parameters are [*,*....]
解决办法:
》自定义spring configuration 如:
@Configuration
@AutoConfigureAfter(PageHelperAutoConfiguration.class)
public class CustomMybatisAutoConfiguration {
@Autowired
private List sqlSessionFactoryList;
@PostConstruct
public void addMyInterceptor() {
for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
sqlSessionFactory.getConfiguration().addInterceptor(new EntitledQueryInterceptor(entitledMapperValueResolver()));
}
}
@Bean
public EntitledMapperValueResolver entitledMapperValueResolver() {
return new EntitledMapperValueResolver();
}
}
PS:责任链模式