小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

深入理解Mybatis插件開(kāi)發(fā)

 甘甘灰 2019-04-08

背景

  • Mybatis插件典型適用場(chǎng)景

  • Mybatis插件介紹

  • Mybatis插件實(shí)現(xiàn)機(jī)制

  • Mybatis插件開(kāi)發(fā)例子

  • 小結(jié)

背景

關(guān)于Mybatis插件,大部分人都知道,也都使用過(guò),但很多時(shí)候,我們僅僅是停留在表面上,知道Mybatis插件可以在DAO層進(jìn)行攔截,如打印執(zhí)行的SQL語(yǔ)句日志,做一些權(quán)限控制,分頁(yè)等功能;但對(duì)其內(nèi)部實(shí)現(xiàn)機(jī)制,涉及的軟件設(shè)計(jì)模式,編程思想往往沒(méi)有深入的理解。

本篇案例將幫助讀者對(duì)Mybatis插件的使用場(chǎng)景,實(shí)現(xiàn)機(jī)制,以及其中涉及的編程思想進(jìn)行一個(gè)小結(jié),希望對(duì)以后的編程開(kāi)發(fā)工作有所幫助。

注:本案例以mybatis 3.4.7-SNAPSHOT版本為例。

PS:文章是挺久之前寫(xiě)的,當(dāng)時(shí)花了一些心思,存到電腦的word里,今天正好看到,就是里面的源碼都是圖片,哈哈哈,湊合著看吧。

Mybatis插件典型適用場(chǎng)景

分頁(yè)功能

mybatis的分頁(yè)默認(rèn)是基于內(nèi)存分頁(yè)的(查出所有,再截取),數(shù)據(jù)量大的情況下效率較低,不過(guò)使用mybatis插件可以改變?cè)撔袨椋恍枰獢r截StatementHandler類(lèi)的prepare方法,改變要執(zhí)行的SQL語(yǔ)句為分頁(yè)語(yǔ)句即可;

公共字段統(tǒng)一賦值

一般業(yè)務(wù)系統(tǒng)都會(huì)有創(chuàng)建者,創(chuàng)建時(shí)間,修改者,修改時(shí)間四個(gè)字段,對(duì)于這四個(gè)字段的賦值,實(shí)際上可以在DAO層統(tǒng)一攔截處理,可以用mybatis插件攔截Executor類(lèi)的update方法,對(duì)相關(guān)參數(shù)進(jìn)行統(tǒng)一賦值即可;

性能監(jiān)控

對(duì)于SQL語(yǔ)句執(zhí)行的性能監(jiān)控,可以通過(guò)攔截Executor類(lèi)的update, query等方法,用日志記錄每個(gè)方法執(zhí)行的時(shí)間;

其它

其實(shí)mybatis擴(kuò)展性還是很強(qiáng)的,基于插件機(jī)制,基本上可以控制SQL執(zhí)行的各個(gè)階段,如執(zhí)行階段,參數(shù)處理階段,語(yǔ)法構(gòu)建階段,結(jié)果集處理階段,具體可以根據(jù)項(xiàng)目業(yè)務(wù)來(lái)實(shí)現(xiàn)對(duì)應(yīng)業(yè)務(wù)邏輯。

Mybatis插件介紹

什么是Mybatis插件

與其稱(chēng)為Mybatis插件,不如叫Mybatis攔截器,更加符合其功能定位,實(shí)際上它就是一個(gè)攔截器,應(yīng)用代理模式,在方法級(jí)別上進(jìn)行攔截。

支持?jǐn)r截的方法

  • 執(zhí)行器Executor(update、query、commit、rollback等方法);

  • 參數(shù)處理器ParameterHandler(getParameterObject、setParameters方法);

  • 結(jié)果集處理器ResultSetHandler(handleResultSets、handleOutputParameters等方法);

  • SQL語(yǔ)法構(gòu)建器StatementHandler(prepare、parameterize、batch、update、query等方法);

攔截階段

那么這些類(lèi)上的方法都是在什么階段被攔截的呢?為理解這個(gè)問(wèn)題,我們先看段簡(jiǎn)單的代碼(摘自mybatis源碼中的單元測(cè)試SqlSessionTest類(lèi)),來(lái)了解下典型的mybatis執(zhí)行流程,如下代碼所示:

image

以上代碼主要完成以下功能:

  • 讀取mybatis的xml配置文件信息

  • 通過(guò)SqlSessionFactoryBuilder創(chuàng)建SqlSessionFactory對(duì)象

  • 通過(guò)SqlSessionFactory獲取SqlSession對(duì)象

  • 執(zhí)行SqlSession對(duì)象的selectList方法,查詢(xún)結(jié)果

  • 關(guān)閉SqlSession

如下是時(shí)序圖,在整個(gè)時(shí)序圖中,涉及到mybatis插件部分已標(biāo)紅,基本上就是體現(xiàn)在上文中提到的四個(gè)類(lèi)上,對(duì)這些類(lèi)上的方法進(jìn)行攔截。

image

Mybatis插件實(shí)現(xiàn)機(jī)制

插件配置信息的加載

先來(lái)看下mybatis是如何加載插件配置的,對(duì)應(yīng)的xml配置信息如下:

image

對(duì)應(yīng)的解析代碼如下,主要做以下工作:

  1. 根據(jù)解析到的類(lèi)信息創(chuàng)建Interceptor對(duì)象;

  2. 調(diào)用setProperties方法設(shè)置屬性變量;

  3. 添加到Configuration的interceptorChain攔截器鏈中;

image

以上邏輯對(duì)應(yīng)的時(shí)序圖如下:

image

代理對(duì)象的生成

Mybatis插件的實(shí)現(xiàn)機(jī)制主要是基于動(dòng)態(tài)代理實(shí)現(xiàn)的,其中最為關(guān)鍵的就是代理對(duì)象的生成,所以有必要來(lái)了解下這些代理對(duì)象是如何生成的。

Executor代理對(duì)象

image

ParameterHandler代理對(duì)象

image

ResultSetHandler代理對(duì)象

image

StatementHandler代理對(duì)象

image

觀(guān)察源碼,發(fā)現(xiàn)這些可攔截的類(lèi)對(duì)應(yīng)的對(duì)象生成都是通過(guò)InterceptorChain的pluginAll方法來(lái)創(chuàng)建的,進(jìn)一步觀(guān)察pluginAll方法,如下:

image

遍歷所有攔截器,調(diào)用攔截器的plugin方法生成代理對(duì)象,注意生成代理對(duì)象重新賦值給target,所以如果有多個(gè)攔截器的話(huà),生成的代理對(duì)象會(huì)被另一個(gè)代理對(duì)象代理,從而形成一個(gè)代理鏈條,執(zhí)行的時(shí)候,依次執(zhí)行所有攔截器的攔截邏輯代碼;

接下來(lái)看一下我們?cè)诰帉?xiě)攔截器的時(shí)候,一個(gè)典型的plugin方法實(shí)現(xiàn)方式,如下:

image

再進(jìn)一步查看wrap方法,如下:

典型的動(dòng)態(tài)代理實(shí)現(xiàn),調(diào)用的是Proxy.newProxyInstance方法來(lái)生成代理對(duì)象。

image

以上邏輯對(duì)應(yīng)的時(shí)序圖如下,這里我們假設(shè)聲明了兩個(gè)攔截器,那么在創(chuàng)建target代理對(duì)象的時(shí)候,最終返回的代理對(duì)象proxy2,實(shí)際上代理了proxy1,而proxy1又代理了target,:

image

攔截邏輯的執(zhí)行

由于真正去執(zhí)行Executor、ParameterHandler、ResultSetHandler和StatementHandler類(lèi)中的方法的對(duì)象是代理對(duì)象(建議將代理對(duì)象轉(zhuǎn)為class文件,反編譯查看其結(jié)構(gòu),幫助理解),所以在執(zhí)行方法時(shí),首先調(diào)用的是Plugin類(lèi)(實(shí)現(xiàn)了InvocationHandler接口)的invoke方法,如下:

首先根據(jù)執(zhí)行方法所屬類(lèi)獲取攔截器中聲明需要攔截的方法集合;

判斷當(dāng)前方法需不需要執(zhí)行攔截邏輯,需要的話(huà),執(zhí)行攔截邏輯方法(即Interceptor接口的intercept方法實(shí)現(xiàn)),不需要?jiǎng)t直接執(zhí)行原方法。

image

可以關(guān)注下Interceptor接口的intercept方法實(shí)現(xiàn),一般需要用戶(hù)自定義實(shí)現(xiàn)邏輯,其中有一個(gè)重要參數(shù),即Invocation類(lèi),通過(guò)改參數(shù)我們可以獲取執(zhí)行對(duì)象,執(zhí)行方法,以及執(zhí)行方法上的參數(shù),從而進(jìn)行各種業(yè)務(wù)邏輯實(shí)現(xiàn),一般在該方法的最后一句代碼都是invocation.proceed()(內(nèi)部執(zhí)行method.invoke方法),否則將無(wú)法執(zhí)行下一個(gè)攔截器的intercept方法。

以上邏輯對(duì)應(yīng)的時(shí)序圖如下,這里我們以執(zhí)行executor對(duì)象的query方法為例,且假設(shè)有兩個(gè)攔截器存在:

image

Mybatis插件開(kāi)發(fā)例子

這里以分頁(yè)插件為例,來(lái)了解下一般mybatis插件的編寫(xiě)規(guī)則,如下所示:

主要需要實(shí)現(xiàn)三個(gè)方法

  1. intercept:在此實(shí)現(xiàn)自己的攔截邏輯,可從Invocation參數(shù)中拿到執(zhí)行方法的對(duì)象,方法,方法參數(shù),從而實(shí)現(xiàn)各種業(yè)務(wù)邏輯, 如下代碼所示,從invocation中獲取的statementHandler對(duì)象即為被代理對(duì)象,基于該對(duì)象,我們獲取到了執(zhí)行的原始SQL語(yǔ)句,以及prepare方法上的分頁(yè)參數(shù),并更改SQL語(yǔ)句為新的分頁(yè)語(yǔ)句,最后調(diào)用invocation.proceed()返回結(jié)果。

  2. plugin:生成代理對(duì)象;

  3. setProperties:設(shè)置一些屬性變量;

image

小結(jié)

簡(jiǎn)單的說(shuō),mybatis插件就是對(duì)ParameterHandler、ResultSetHandler、StatementHandler、Executor這四個(gè)接口上的方法進(jìn)行攔截,利用JDK動(dòng)態(tài)代理機(jī)制,為這些接口的實(shí)現(xiàn)類(lèi)創(chuàng)建代理對(duì)象,在執(zhí)行方法時(shí),先去執(zhí)行代理對(duì)象的方法,從而執(zhí)行自己編寫(xiě)的攔截邏輯,所以真正要用好mybatis插件,主要還是要熟悉這四個(gè)接口的方法以及這些方法上的參數(shù)的含義;

另外,如果配置了多個(gè)攔截器的話(huà),會(huì)出現(xiàn)層層代理的情況,即代理對(duì)象代理了另外一個(gè)代理對(duì)象,形成一個(gè)代理鏈條,執(zhí)行的時(shí)候,也是層層執(zhí)行;

關(guān)于mybatis插件涉及到的設(shè)計(jì)模式和軟件思想如下:

  1. 設(shè)計(jì)模式:代理模式、責(zé)任鏈模式;

  2. 軟件思想:AOP編程思想,降低模塊間的耦合度,使業(yè)務(wù)模塊更加獨(dú)立;

一些注意事項(xiàng):

  1. 不要定義過(guò)多的插件,代理嵌套過(guò)多,執(zhí)行方法的時(shí)候,比較耗性能;

  2. 攔截器實(shí)現(xiàn)類(lèi)的intercept方法里最后不要忘了執(zhí)行invocation.proceed()方法,否則多個(gè)攔截器情況下,執(zhí)行鏈條會(huì)斷掉;

最后

歡迎工作一到五年的Java工程師朋友們加入Java架構(gòu)開(kāi)發(fā): 957734884,群內(nèi)提供免費(fèi)的Java架構(gòu)學(xué)習(xí)資料(里面有高可用、高并發(fā)、高性能及分布式、Jvm性能調(diào)優(yōu)、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個(gè)知識(shí)點(diǎn)的架構(gòu)資料)合理利用自己每一分每一秒的時(shí)間來(lái)學(xué)習(xí)提升自己,不要再用'沒(méi)有時(shí)間“來(lái)掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來(lái)的自己一個(gè)交代!

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀(guān)點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多