<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
此時commentAnalyses為Page物件(PageHelper外掛包內定義的)
而Page物件繼承自JDK中的ArrayList,擴充套件並封裝了一些page相關的欄位,如頁碼,每頁大小,總記錄數,總頁數等。
我們就加了一行,它是如何幫助我們實現分頁的呢?請往下看。
我們看這一行PageHelper.startPage(pageIndex, pageSize);
做了什麼。這個類中過載了好多個startPage方法,最終呼叫到如下的一個方法
可以看到該方法將分頁資訊作為構造器引數範例化Page物件,呼叫SqlUtil.getLocalPage()
獲取一箇舊的Page物件,最後呼叫SqlUtil.setLocalPage(page);
把新建立的Page物件set進去。
我們看看這兩個方法做了什麼。如下,很簡單,從ThreadLocal中獲取Page物件,將Page物件set到ThreadLocal中。知道ThreadLocal作用的不用多說,不知道的可以理解為用於儲存本地變數,並與執行緒繫結。
看到這我們暫且將這一行的作用記為,建立並儲存Page物件(分頁資訊)到ThreadLocal中。
那麼既然儲存了,就有使用的地方。
我通過程式碼追蹤的方式定位到被呼叫的地方,通過回溯,發現是從這個類com.github.pagehelper.dialect.AbstractDialect
發起呼叫的
點進去看了一下,主要是取出Page物件用於做一些判斷,或儲存page相關的資訊。應該後續會涉及到
上述AbstractDialect類中的這些方法再回溯,指向了
com.github.pagehelper.util.SqlUtil#doIntercept
方法,intercep呼叫了doIntercep方法,
繼續往上追蹤來到了com.github.pagehelper.PageHelper#intercept
,這是Interceptor介面的方法。
然後是org.apache.ibatis.plugin.Plugin#invoke
呼叫了com.github.pagehelper.PageHelper#intercept
。
可以看到PageHelper實現了Interceptor,這個介面是Mybatis官方提供的,中文意思是攔截器,所以有可能是通過實現這個攔截器做了某些操作來實現分頁的。
通過程式碼追蹤我們看到Interceptor的intercept方法是在Mybatis的一個org.apache.ibatis.plugin.Plugin
類的invoke方法中呼叫的,而這個Plugin類實現了JDK的java.lang.reflect.InvocationHandler
介面,這是JDK代理介面。
這個Plugin中有一個wrap方法會返回一個代理類,所以當呼叫這個代理類的方法時就會走到上面的invoke方法,就可能會進到攔截器的intercept方法。
所以我們看這個warp在哪調的,就知道啥時候建立這個代理類。就是在上面的PageHelper中,再貼一下程式碼
而這個PageHelper中的plugin方法是實現自Interceptor攔截器介面,所以會有一個地方統一調這個方法,往上追溯就會發現是在org.apache.ibatis.plugin.InterceptorChain
攔截器鏈中呼叫的,如下。
該類有一個List儲存所有攔截器,還有三個方法,分別是pluginAll用於呼叫所有攔截器的plugin方法,addInterceptor新增攔截器,getInterceptors獲取攔截器鏈。
看到這大致明白了它的原理,PageHelper通過實現Mybatis的Interceptor介面實現分頁,Mybatis通過InterceptorChain呼叫所有Interceptor。
那麼我們看看Mybatis的攔截器是什麼時候新增到攔截器鏈,什麼時候被呼叫的。
通過程式碼追溯,發現在Configuration的addInterceptor方法中呼叫新增方法,Configuration.addInterceptor是在XMLConfigBuilder的pluginElement方法中被呼叫
而XMLConfigBuilder是解析XML方式的Mybatis的設定的,顧名思義pluginElement方法是解析XML中plugin相關的設定節點的
而我們確實在XML中設定了plugin
所以我們現在知道了mybatis的攔截器是在Mybatis解析組態檔時,解析plugins節點時新增到InterceptorChain中的。
攔截器什麼時候呼叫的。我們看InterceptorChain的pluginAll方法在哪調的,通過程式碼追蹤有如下四個地方呼叫攔截器鏈
而PageHelper這個攔截器,我們可以發現這個類上有一個@Intercepts註解,這個註解接收的值為@Signature註解,在Signature註解設定了,Executor.class,query還有四個class:MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class。
瞭解Mybatis的外掛機制的就明白了,這一行設定的意思是攔截Executor中的query方法,方法參數列型別是MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class,就是下面這個方法。
所以看到這,我們可以斷定InterceptorChain的pluginAll方法在上述呼叫點的第四個,也就是org.apache.ibatis.session.Configuration#newExecutor(org.apache.ibatis.transaction.Transaction, org.apache.ibatis.session.ExecutorType)
,可想而知newExecutor,也就是建立Executor範例,可以斷定,建立Executor時通過PageHelper的plugin方法包裝了Executor,返回的是Executor的代理類。下面會講到建立動態代理。
我們在正向回顧一下,如何調到PageHelper的。首先進入到pluginAll
然後會調到PageHelper的plugin方法,內部又調Plugin的warp方法
我們看看Plugin.wrap方法幹了啥,程式碼如下。程式碼跟過來我們知道現在的target是Executor,interceptor是PageHelper。首先獲取PageHelper攔截資訊,然後篩選target是否是需要攔截的型別,這裡會進入if判斷邏輯,返回Executor的代理物件。
所以這時建立的Executor範例是代理物件,那麼就會在某個時候呼叫代理的invoke方法(org.apache.ibatis.plugin.Plugin#invoke),invoke調Interceptor攔截器的intercept方法,從而調PageHelper的intercept方法執行分頁邏輯
org.apache.ibatis.plugin.Plugin#invoke ==》 com.github.pagehelper.PageHelper#intercept
因為返回的是Executor的動態代理,所以肯定是呼叫Executor的某個方法時觸發進到invoke方法,具體在哪調的不好找。我們通過打斷點的方式看是從哪進invoke方法的,首先斷點打到Plugin的invoke方法內
通過呼叫棧看到是org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)
調過來的,在invoke方法內判斷了目標方法是不是我們要攔截的方法,因為PageHelper上註解的也是攔截這個方法,所以會進入到Plugin的invoke方法的第61行。所以就會進入到PageHelper的intercept方法,執行具體的攔截邏輯。
思路就是拼SQL。
通過程式碼跟蹤,最終的分頁邏輯是在com.github.pagehelper.util.SqlUtil#doIntercept方法中,第162行,獲取分頁SQL,
呼叫
com.github.pagehelper.dialect.AbstractDialect#getPageSql(org.apache.ibatis.mapping.MappedStatement, org.apache.ibatis.mapping.BoundSql, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.cache.CacheKey)
在com.github.pagehelper.dialect.AbstractDialect#getPageSql(org.apache.ibatis.mapping.MappedStatement, org.apache.ibatis.mapping.BoundSql, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.cache.CacheKey)
中呼叫com.github.pagehelper.dialect.AbstractDialect#getPageSql(java.lang.String, com.github.pagehelper.Page, org.apache.ibatis.session.RowBounds,org.apache.ibatis.cache.CacheKey)
,是一個抽象方法,具體實現有好多種
我們看mysql的,在原始SQL 拼接了" limit ?,?"
以上是PageHelper實現分頁的原理,總結一下:
Mybatis在四個地方留了擴充套件點,可以通過自定義攔截器實現Interceptor介面的plugin方法,執行自定義邏輯,可以通過該方法對Executor、ParameterHandler、ResultSetHandler、StatementHandler四個物件進行增強、擴充套件。
PageHelper實現了Interceptor介面,它的plugin方法呼叫Plugin.wrap方法對目標物件進行包裝,包裝成一個代理物件並返回,代理類的實現就是Plugin自身。
Plugin.wrap方法判斷目標物件是否需要返回代理物件,判斷依據是:Interceptor實現類(這裡是PageHelper)上註解標註的類是否包含目標物件所屬類。這裡PageHelper上註解標註引數為Executor物件,所以建立Executor物件會返回代理物件。
當呼叫Executor物件的方法時會進入到Plugin.invoke方法。invoke方法會判斷是否需要走攔截器的intercept方法,判斷方式是取攔截器上的註解標註的方法,這裡PageHelper標註的為executor.query(四個引數的那個),所以調這個時才會被攔截器攔截,其餘方法還用原始物件呼叫。
PageHelper的intercept方法呼叫SqlUtil的intercept方法最終調SqlUtil.doIntercept方法。在這個方法裡會執行count語句,並將結果放到page物件裡,然後判斷需要分頁,則將分頁sql拼在原始sql上,然後執行。
簡單來說就是通過mybatis的攔截器和外掛實現的,PageHelper實現了Interceptor攔截器介面,並攔截Executor的query方法,在執行前PageHelper會在原始SQL前拼裝分頁相關的SQL。
PageHelper支援以下資料庫的分頁:Db2、Hsqldbt 、Informix、MySq、Oracle 、SqlServer2012、SqlServer
mybatis的外掛Plugin是通過JDK動態代理對目標物件進行增強
到此這篇關於Mybatis第三方PageHelper分頁外掛使用與原理的文章就介紹到這了,更多相關Mybatis第三方PageHelper分頁外掛內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45