最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

mybatis-plugin插件執(zhí)行原理解析

 更新時間:2022年10月19日 09:26:26   作者:尋找的路上  
這篇文章主要介紹了mybatis-plugin插件執(zhí)行原理,我們就需要來研究下Executor,ParameterHandler,ResultSetHandler,StatementHandler這4個對象的具體跟sql相關(guān)的方法,然后再進行修改,就可以直接起到aop的作用,需要的朋友可以參考下

mybatis-plugin插件執(zhí)行原理

今天主要是在看mybatis的主流程源碼,其中比較感興趣的是mybatis的plugin功能,這里主要記錄下mybatis-plugin的插件功能原理。

plugin集合列表:在構(gòu)建SqlSessionFactory時,通過解析配置或者plugin-bean的注入,會將所有的mybatis-plugin都收集到Configuration
對象的interceptorChain屬性中。InterceptorChain類定義如下:

public class InterceptorChain {

  private final List<Interceptor> interceptors = new ArrayList<>();

  public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
  }

  public void addInterceptor(Interceptor interceptor) {
    interceptors.add(interceptor);
  }

  public List<Interceptor> getInterceptors() {
    return Collections.unmodifiableList(interceptors);
  }

}

plugin作用對象:Executor,ParameterHandler,ResultSetHandler,StatementHandler,這4個對象在mybatis執(zhí)行sql的過程中
有不同的作用。

Executor:sql執(zhí)行的具體操作對象。
ParameterHandler:sql執(zhí)行前的參數(shù)處理對象。
ResultSetHandler:sql執(zhí)行后的結(jié)果集處理對象。
StatementHandler:具體送到數(shù)據(jù)庫執(zhí)行的sql操作對象。

plugin作用原理:類似AOP,使用JDK動態(tài)代理,只不過mybatis的增強對象不是所有對象,而是上面陳列的4個對象而已。
在4個對象創(chuàng)建時,都會對各個對象進行判斷,是否需要進行插件化。比如下面的插件:

@Intercepts({@Signature( type= Executor.class,  method = "query", args ={
        MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class
})})
    public class ExamplePlugin implements Interceptor {

    //  分頁   讀寫分離    Select  增刪改

        public Object intercept(Invocation invocation) throws Throwable {
            System.out.println("代理");
        Object[] args = invocation.getArgs();
        MappedStatement ms= (MappedStatement) args[0];
        // 執(zhí)行下一個攔截器、直到盡頭
        return invocation.proceed();
    }
}

該插件將會在Executor該對象創(chuàng)建時,使用該插件進行增強。在新開一個sqlSession時,將會創(chuàng)建Executor對象。跟蹤到具體方法:

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    /**
     * 判斷執(zhí)行器的類型
     * 批量的執(zhí)行器
     */
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      //可重復(fù)使用的執(zhí)行器
      executor = new ReuseExecutor(this, transaction);
    } else {
      //簡單的sql執(zhí)行器對象
      executor = new SimpleExecutor(this, transaction);
    }
    //判斷mybatis的全局配置文件是否開啟緩存
    if (cacheEnabled) {
      //把當(dāng)前的簡單的執(zhí)行器包裝成一個CachingExecutor
      executor = new CachingExecutor(executor);
    }
    /**
     * TODO:調(diào)用所有的攔截器對象plugin方法
     * 插件: 責(zé)任鏈+ 裝飾器模式(動態(tài)代理)
     */
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }

我們找到interceptorChain.pluginAll方法:

public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
  }

發(fā)現(xiàn)會通過已加載的所有plugin列表中,逐個遍歷去篩選出符合Executor類型的插件,再通過具體插件的interceptor.plugin方法去創(chuàng)建
Executor的代理對象。

public interface Interceptor {

  Object intercept(Invocation invocation) throws Throwable;

  default Object plugin(Object target) {
    return Plugin.wrap(target, this);
  }
  default void setProperties(Properties properties) {
    // NOP
  }
}

再看到具體的Plugin.wrap(target, this)方法:

  public static Object wrap(Object target, Interceptor interceptor) {
    // 獲得interceptor配置的@Signature的type
    Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
    // 當(dāng)前代理類型
    Class<?> type = target.getClass();
    // 根據(jù)當(dāng)前代理類型 和 @signature指定的type進行配對, 配對成功則可以代理
    Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
    if (interfaces.length > 0) {
      return Proxy.newProxyInstance(
          type.getClassLoader(),
          interfaces,
          new Plugin(target, interceptor, signatureMap));
    }
    return target;
  }

這里我們就很清楚了,通過@Signature注解上的type、method、args屬性去匹配,如果找到符合的,就會為對象創(chuàng)建代理對象,并返回代理對象。

責(zé)任鏈設(shè)計模式:因為一個增強對象可能會有多個plugin的增強邏輯,所以在執(zhí)行的時候使用的是責(zé)任鏈設(shè)計模式。

因為Plugin.wrap()方法新建的代理對象中使用的InvocationHandler對象是Plugin本身,所以在執(zhí)行方法的時候首先要調(diào)用它的invoke方法,

@Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      Set<Method> methods = signatureMap.get(method.getDeclaringClass());
      if (methods != null && methods.contains(method)) {
        return interceptor.intercept(new Invocation(target, method, args));
      }
      return method.invoke(target, args);
    } catch (Exception e) {
      throw ExceptionUtil.unwrapThrowable(e);
    }
  }

當(dāng)我們執(zhí)行Executor的query方法時,符合if (methods != null && methods.contains(method)) {條件,這時就會去執(zhí)行具體插件的增強方法,interceptor.intercept,
然后再通過傳遞new Invocation(target, method, args)對象,在插件執(zhí)行完之后,再調(diào)用invocation.proceed()去執(zhí)行下一個插件邏輯。
如下是對Executor的query方法添加了2個插件的場景:

總結(jié):如果我們的業(yè)務(wù)需要我們?nèi)ゾ帉憇ql插件,那我們就需要來研究下Executor,ParameterHandler,ResultSetHandler,StatementHandler這4個對象的具體跟sql相關(guān)的方法,
然后再進行修改,就可以直接起到aop的作用。

到此這篇關(guān)于mybatis-plugin插件執(zhí)行原理的文章就介紹到這了,更多相關(guān)mybatis-plugin插件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • IDEA搭建配置Java?Web項目的詳細步驟

    IDEA搭建配置Java?Web項目的詳細步驟

    這篇文章詳細介紹了如何使用IDEA創(chuàng)建和配置JavaWeb項目,包括項目結(jié)構(gòu)設(shè)置、WEB-INF目錄和jsp文件的創(chuàng)建,以及Tomcat的配置,是Java初學(xué)者的實用指南,需要的朋友可以參考下
    2024-10-10
  • Java使用觀察者模式實現(xiàn)氣象局高溫預(yù)警功能示例

    Java使用觀察者模式實現(xiàn)氣象局高溫預(yù)警功能示例

    這篇文章主要介紹了Java使用觀察者模式實現(xiàn)氣象局高溫預(yù)警功能,結(jié)合完整實例形式分析了java觀察者模式實現(xiàn)氣象局高溫預(yù)警的相關(guān)接口定義、使用、功能操作技巧,并總結(jié)了其設(shè)計原則與適用場合,具有一定參考借鑒價值,需要的朋友可以參考下
    2018-04-04
  • 在Java的Hibernate框架中對數(shù)據(jù)庫數(shù)據(jù)進行查詢操作

    在Java的Hibernate框架中對數(shù)據(jù)庫數(shù)據(jù)進行查詢操作

    這篇文章主要介紹了Java的Hibernate框架中對數(shù)據(jù)庫數(shù)據(jù)進行查詢操作的方法,Hibernate是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下
    2015-12-12
  • Java中字符串和byte數(shù)組之間的簡單轉(zhuǎn)換方法

    Java中字符串和byte數(shù)組之間的簡單轉(zhuǎn)換方法

    這篇文章主要給大家介紹了關(guān)于Java中字符串和byte數(shù)組之間的簡單轉(zhuǎn)換方法,Java中將String類型轉(zhuǎn)換為byte[]類型,可以使用String的getBytes()方法,還有很多其他的辦法,需要的朋友可以參考下
    2023-08-08
  • Maven項目在new module后,pom文件顯示為Ignored pom.xml問題

    Maven項目在new module后,pom文件顯示為Ignored pom.xml問題

    在Maven項目中,若創(chuàng)建過同名module后刪除,再次創(chuàng)建時可能導(dǎo)致pom.xml文件被IDEA忽略,原因是IDEA保留了之前module的痕跡,導(dǎo)致重建時將其視為已刪除的module,解決方法是進入IDEA設(shè)置,找到Maven的Ignored Files設(shè)置
    2024-09-09
  • 如何用Java實現(xiàn)排列組合算法

    如何用Java實現(xiàn)排列組合算法

    本文主要介紹了如何用Java實現(xiàn)排列組合算法,對算法感興趣的同學(xué),可以參考一下,理解其原理,并且試驗一下。
    2021-05-05
  • java基礎(chǔ)篇之Date類型最常用的時間計算(相當(dāng)全面)

    java基礎(chǔ)篇之Date類型最常用的時間計算(相當(dāng)全面)

    這篇文章主要給大家介紹了關(guān)于java基礎(chǔ)篇之Date類型最常用的時間計算的相關(guān)資料,Java中的Date類是用來表示日期和時間的類,它提供了一些常用的方法來處理日期和時間的操作,需要的朋友可以參考下
    2023-12-12
  • Java使用Scanner類進行控制臺輸入實現(xiàn)方法

    Java使用Scanner類進行控制臺輸入實現(xiàn)方法

    這篇文章主要介紹了Java使用Scanner類進行控制臺輸入實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • Mybatis 一級緩存與二級緩存的實現(xiàn)

    Mybatis 一級緩存與二級緩存的實現(xiàn)

    mybatis作為一個流行的持久化工具,緩存必然是缺少不了的組件。通過這篇文章,就讓我們來了解一下一級緩存與二級緩存的實現(xiàn),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-05-05
  • JAVA基本概念詳解

    JAVA基本概念詳解

    本文主要介紹了Java的基本概念。具有很好的參考價值,下面跟著小編一起來看下吧,希望能夠給你帶來幫助
    2021-11-11

最新評論

教育| 齐齐哈尔市| 桐柏县| 南阳市| 辛集市| 洪江市| 克山县| 民丰县| 阳谷县| 林州市| 水城县| 闸北区| 海伦市| 松滋市| 聊城市| 双鸭山市| 宁化县| 吉安市| 修水县| 灵寿县| 关岭| 惠州市| 利辛县| 浮山县| 长顺县| 通海县| 泾阳县| 太湖县| 五常市| 兴安盟| 阿坝县| 铁力市| 岑溪市| 江永县| 正宁县| 大连市| 威远县| 镇沅| 扎囊县| 肃南| 松江区|