問題
面試官:前面說了很多的關於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;
}
- 創建StatementHandler
- 插件增強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);
}
}
- 創建StatementHandler
總結
問題是怎麼保證數據權限控制插件先於分頁插件執行。
通過分析Mybatis的的組件創建過程,得到由Executor創建StatementHandler,所以,數據權限控制插件攔截Executor接口,保證數據權限控制插件的增強邏輯先執行。
同學們我答對了嗎?
還有其他的辦法嗎?
歡迎討論學習
使用JDK API實現動態代理和源碼分析
Mybatis 插件和動態代理
面試官問,爲啥Mybatis的接口不需要實現類