PageHelper 是Mybaties中的一個分頁插件。其maven坐標
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.1.10</version> </dependency>
目前以更新到5.1 ,新的版本好像和以前的版本有些差別 這里分析下以前的版本
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>4.1.3</version> </dependency>
其和Mybaties的配置整合不累贅。只看看如何實現分頁的原理。
先說如果在代碼中使用 ,很簡單如下,一行代碼 ,在查詢的時候就自動實現分頁:
PageHelper.startPage(params.getPageIndex(), params.getPageSize(), true, true);
其startPage方法重載 :
跟蹤代碼 進入到PageHelper這個類 看到這個類繼承了Interceptor 接口,這個接口是Mybaties 提供的
public class PageHelper implements Interceptor { //sql工具類 private SqlUtil sqlUtil; //屬性參數信息 private Properties properties; //配置對象方式 private SqlUtilConfig sqlUtilConfig; //自動獲取dialect,如果沒有setProperties或setSqlUtilConfig,也可以正常進行 private boolean autoDialect = true; //運行時自動獲取dialect private boolean autoRuntimeDialect; //多數據源時,獲取jdbcurl后是否關閉數據源 private boolean closeConn = true; //緩存 private Map<String, SqlUtil> urlSqlUtilMap = new ConcurrentHashMap<String, SqlUtil>();
...
public interface Interceptor { Object intercept(Invocation invocation) throws Throwable; Object plugin(Object target); void setProperties(Properties properties); }
可以看到 Interceptor 類中有個攔截方法intercept ,這個方法就應該是攔截器的執行方法 。繼續跟蹤這個方法在哪里有引用 。發現只在類plugin類有引用

可以看到在method.invoke 執行之前 ,攔截器執行了攔截方法 ,而 pageHelper這個類就是個攔截器 。再看看Plugin這個類 實現了動態代理 的接口 InvocationHandler 。其私有構造方法在靜態方法wrap中調用 ,說明這能通過wrap這個方法獲取Plugin實例,wrap方法對參數target做了個動態代理 。所以說target執行方法是通過代理 Plugin 執行invoke方法 。

那么wrap方法中的target 又是什么呢 ???。wrap方法又是在什么時候調用的呢 ?一層一層的跟蹤 如下代碼 。

又回到了 pageHelp 這個類,在類plugin方法中調用了wrap方法,而且target只有在屬於Executor 的時候把target做了代理。跟蹤代碼發現Plugin方法又在攔截器鏈InterceptorChain方法pluginAll調用
pluginAll 就是把target這個類按攔截器的數量做了多次對plugin的代理 ,而每個plugin中都有一個不同的攔截器 Interceptor。而target在這可以把它 看做是執行器Executor 了 。因為前面說過只對Executor 攔截,再看看pluginAll方法的引用, 在類 Configuration如下
可以看到在Configuration創建 Executor 、ParameterHandler、ResultSetHandler、StatementHandler 都有對做代理 ,對攔截器進行攔截執行。但是pageHelp只對Executor 做了代理 。回過頭來看看攔截器PageHelp做了什么 ?
/** * Mybatis攔截器方法 * * @param invocation 攔截器入參 * @return 返回執行結果 * @throws Throwable 拋出異常 */ public Object intercept(Invocation invocation) throws Throwable { if (autoRuntimeDialect) { SqlUtil sqlUtil = getSqlUtil(invocation); return sqlUtil.processPage(invocation); } else { if (autoDialect) { initSqlUtil(invocation); } return sqlUtil.processPage(invocation); } }
方法最終就是通過sqlUtil在執行sql中加了分頁參數 。完成分頁 。
