面试官:前面说了很多的关于Mybatis的知识点,现在我们说说一个实际的问题。
我们需要多个Mybatis
插件配合完成一个功能,例如完成数据权限
。
通过组织架构树
控制数据访问的范围,所以使用Mybatis插件
,拦截修改SQL
,添加类似in(createorId1,createorId2,createorId3,......)
这样的SQL。
但是和分页插件
冲突,需要控制让这个数据权限控制插件先执行,分页插件后执行,您有什么好的方法吗?
我:问题好长,让我想想。
我知道有一个在configration中有个interceptorChain
,在创建Executor、ParameterHandler、StatementHandler、ResultSetHandle的时候,通过Interceptor的plugin方法,增强对象。那怎么控制增强的执行顺序呢?
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);// 1
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);//2
return statementHandler;
}
插件在增强逻辑是在Interceptor的intercept
方法中,是代理对象的增强逻辑。
Mybatis执行的真正的入口是Executor,在Executor中创建的StatementHandler
,分页一般拦截的是StatementHandler
接口,所以我们可以让我们新的拦截器,拦截Executor
的query
方法,这样就可以保证先执行了,
如下:
MybatisSimpleExecutor.java
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);// 1
stmt = prepareStatement(handler, ms.getStatementLog(), false);
return stmt == null ? Collections.emptyList() : handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
问题是怎么保证数据权限控制插件先于分页插件执行。
通过分析Mybatis的的组件创建过程,得到由Executor创建StatementHandler,所以,数据权限控制插件拦截Executor接口,保证数据权限控制插件的增强逻辑先执行。
同学们我答对了吗?
还有其他的办法吗?
欢迎讨论学习
使用JDK API实现动态代理和源码分析
Mybatis 插件和动态代理
面试官问,为啥Mybatis的接口不需要实现类
面试官问,Mybatis插件增强逻辑的顺序怎么控制