乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

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

       甘甘灰 2019-04-08

      背景

      • Mybatis插件典型適用場景

      • Mybatis插件介紹

      • Mybatis插件實現(xiàn)機制

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

      • 小結

      背景

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

      本篇案例將幫助讀者對Mybatis插件的使用場景,實現(xiàn)機制,以及其中涉及的編程思想進行一個小結,希望對以后的編程開發(fā)工作有所幫助。

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

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

      Mybatis插件典型適用場景

      分頁功能

      mybatis的分頁默認是基于內存分頁的(查出所有,再截?。?,數(shù)據(jù)量大的情況下效率較低,不過使用mybatis插件可以改變該行為,只需要攔截StatementHandler類的prepare方法,改變要執(zhí)行的SQL語句為分頁語句即可;

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

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

      性能監(jiān)控

      對于SQL語句執(zhí)行的性能監(jiān)控,可以通過攔截Executor類的update, query等方法,用日志記錄每個方法執(zhí)行的時間;

      其它

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

      Mybatis插件介紹

      什么是Mybatis插件

      與其稱為Mybatis插件,不如叫Mybatis攔截器,更加符合其功能定位,實際上它就是一個攔截器,應用代理模式,在方法級別上進行攔截。

      支持攔截的方法

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

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

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

      • SQL語法構建器StatementHandler(prepare、parameterize、batch、update、query等方法);

      攔截階段

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

      image

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

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

      • 通過SqlSessionFactoryBuilder創(chuàng)建SqlSessionFactory對象

      • 通過SqlSessionFactory獲取SqlSession對象

      • 執(zhí)行SqlSession對象的selectList方法,查詢結果

      • 關閉SqlSession

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

      image

      Mybatis插件實現(xiàn)機制

      插件配置信息的加載

      先來看下mybatis是如何加載插件配置的,對應的xml配置信息如下:

      image

      對應的解析代碼如下,主要做以下工作:

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

      2. 調用setProperties方法設置屬性變量;

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

      image

      以上邏輯對應的時序圖如下:

      image

      代理對象的生成

      Mybatis插件的實現(xiàn)機制主要是基于動態(tài)代理實現(xiàn)的,其中最為關鍵的就是代理對象的生成,所以有必要來了解下這些代理對象是如何生成的。

      Executor代理對象

      image

      ParameterHandler代理對象

      image

      ResultSetHandler代理對象

      image

      StatementHandler代理對象

      image

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

      image

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

      接下來看一下我們在編寫攔截器的時候,一個典型的plugin方法實現(xiàn)方式,如下:

      image

      再進一步查看wrap方法,如下:

      典型的動態(tài)代理實現(xiàn),調用的是Proxy.newProxyInstance方法來生成代理對象。

      image

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

      image

      攔截邏輯的執(zhí)行

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

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

      判斷當前方法需不需要執(zhí)行攔截邏輯,需要的話,執(zhí)行攔截邏輯方法(即Interceptor接口的intercept方法實現(xiàn)),不需要則直接執(zhí)行原方法。

      image

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

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

      image

      Mybatis插件開發(fā)例子

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

      主要需要實現(xiàn)三個方法

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

      2. plugin:生成代理對象;

      3. setProperties:設置一些屬性變量;

      image

      小結

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

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

      關于mybatis插件涉及到的設計模式和軟件思想如下:

      1. 設計模式:代理模式、責任鏈模式;

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

      一些注意事項:

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

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

      最后

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

        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
        轉藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多