亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

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

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

plugin集合列表:在構(gòu)建SqlSessionFactory時(shí),通過解析配置或者plugin-bean的注入,會(huì)將所有的mybatis-plugin都收集到Configuration
對(duì)象的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作用對(duì)象:Executor,ParameterHandler,ResultSetHandler,StatementHandler,這4個(gè)對(duì)象在mybatis執(zhí)行sql的過程中
有不同的作用。

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

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

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

    //  分頁(yè)   讀寫分離    Select  增刪改

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

該插件將會(huì)在Executor該對(duì)象創(chuàng)建時(shí),使用該插件進(jìn)行增強(qiáng)。在新開一個(gè)sqlSession時(shí),將會(huì)創(chuàng)建Executor對(duì)象。跟蹤到具體方法:

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 {
      //簡(jiǎn)單的sql執(zhí)行器對(duì)象
      executor = new SimpleExecutor(this, transaction);
    }
    //判斷mybatis的全局配置文件是否開啟緩存
    if (cacheEnabled) {
      //把當(dāng)前的簡(jiǎn)單的執(zhí)行器包裝成一個(gè)CachingExecutor
      executor = new CachingExecutor(executor);
    }
    /**
     * TODO:調(diào)用所有的攔截器對(duì)象plugin方法
     * 插件: 責(zé)任鏈+ 裝飾器模式(動(dòng)態(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)會(huì)通過已加載的所有plugin列表中,逐個(gè)遍歷去篩選出符合Executor類型的插件,再通過具體插件的interceptor.plugin方法去創(chuàng)建
Executor的代理對(duì)象。

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進(jìn)行配對(duì), 配對(duì)成功則可以代理
    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屬性去匹配,如果找到符合的,就會(huì)為對(duì)象創(chuàng)建代理對(duì)象,并返回代理對(duì)象。

責(zé)任鏈設(shè)計(jì)模式:因?yàn)橐粋€(gè)增強(qiáng)對(duì)象可能會(huì)有多個(gè)plugin的增強(qiáng)邏輯,所以在執(zhí)行的時(shí)候使用的是責(zé)任鏈設(shè)計(jì)模式。

因?yàn)?code>Plugin.wrap()方法新建的代理對(duì)象中使用的InvocationHandler對(duì)象是Plugin本身,所以在執(zhí)行方法的時(shí)候首先要調(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方法時(shí),符合if (methods != null && methods.contains(method)) {條件,這時(shí)就會(huì)去執(zhí)行具體插件的增強(qiáng)方法,interceptor.intercept
然后再通過傳遞new Invocation(target, method, args)對(duì)象,在插件執(zhí)行完之后,再調(diào)用invocation.proceed()去執(zhí)行下一個(gè)插件邏輯。
如下是對(duì)Executor的query方法添加了2個(gè)插件的場(chǎng)景:

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

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

相關(guān)文章

  • eclipse創(chuàng)建java項(xiàng)目并運(yùn)行的詳細(xì)教程講解

    eclipse創(chuàng)建java項(xiàng)目并運(yùn)行的詳細(xì)教程講解

    eclipse是java開發(fā)的ide工具,是大部分java開發(fā)人員的首選開發(fā)工具,可是對(duì)于一些新Java人員來說,不清楚eclipse怎么運(yùn)行項(xiàng)目?這篇文章主要給大家介紹了關(guān)于eclipse創(chuàng)建java項(xiàng)目并運(yùn)行的相關(guān)資料,需要的朋友可以參考下
    2023-04-04
  • Window搭建部署RocketMQ步驟詳解

    Window搭建部署RocketMQ步驟詳解

    這篇文章主要介紹了Window搭建部署RocketMQ步驟詳解,RocketMq是一個(gè)由阿里巴巴開源的消息中間件,脫胎去阿里每部使用的MetaQ,在設(shè)計(jì)上借鑒了Kafka。,需要的朋友可以參考下
    2019-06-06
  • Java 數(shù)據(jù)結(jié)構(gòu)哈希算法之哈希桶方式解決哈希沖突

    Java 數(shù)據(jù)結(jié)構(gòu)哈希算法之哈希桶方式解決哈希沖突

    實(shí)際上哈希桶是解決哈希表沖突的一種方法。常見的解決沖突的兩種方法:分離鏈接法、開放定址法。其中使用分離鏈接法,得到的對(duì)應(yīng)關(guān)系即為哈希桶
    2022-02-02
  • java selenium XPath 定位實(shí)現(xiàn)方法

    java selenium XPath 定位實(shí)現(xiàn)方法

    本文主要介紹java selenium XPath,這里整理了XPath的資料,并附實(shí)現(xiàn)方法,有需要的小伙伴可以參考下
    2016-08-08
  • Spring?AOP核心功能示例代碼詳解

    Spring?AOP核心功能示例代碼詳解

    AOP面向切面編程,它是一種思想,它是對(duì)某一類事情的集中處理,而AOP是一種思想,而Spring?AOP是一個(gè)框架,提供了一種對(duì)AOP思想的實(shí)現(xiàn),它們的關(guān)系和loC與DI類似,這篇文章主要介紹了Spring?AOP統(tǒng)一功能處理示例代碼,需要的朋友可以參考下
    2023-02-02
  • Java算法中的歸并排序算法代碼實(shí)現(xiàn)

    Java算法中的歸并排序算法代碼實(shí)現(xiàn)

    這篇文章主要介紹了Java算法中的歸并排序算法代碼實(shí)現(xiàn),歸并排序使用的是分治思想(Divide and Conquer),分治,顧名思義,就是分而治之,是將一個(gè)大問題分解成小的子問題來解決,需要的朋友可以參考下
    2023-12-12
  • 基于TCP通信丟包原因總結(jié)(推薦)

    基于TCP通信丟包原因總結(jié)(推薦)

    下面小編就為大家?guī)硪黄赥CP通信丟包原因總結(jié)(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-08-08
  • IntelliJ IDEA失焦自動(dòng)重啟服務(wù)的解決方法

    IntelliJ IDEA失焦自動(dòng)重啟服務(wù)的解決方法

    在使用 IntelliJ IDEA運(yùn)行 SpringBoot 項(xiàng)目時(shí),你可能會(huì)遇到一個(gè)令人困擾的問題,一旦你的鼠標(biāo)指針離開當(dāng)前IDE窗口,點(diǎn)擊其他位置時(shí), IDE 窗口會(huì)失去焦點(diǎn),你的 SpringBoot 服務(wù)就會(huì)自動(dòng)重啟,所以本文給大家介紹了IntelliJ IDEA失焦自動(dòng)重啟服務(wù)的解決方法
    2023-10-10
  • java字符串格式化(String類format方法)

    java字符串格式化(String類format方法)

    這篇文章主要介紹了java字符串格式化(String類format方法),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • JAVA實(shí)現(xiàn)賬戶取款和存款操作

    JAVA實(shí)現(xiàn)賬戶取款和存款操作

    這篇文章主要介紹了JAVA實(shí)現(xiàn)賬戶取款和存款操作,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11

最新評(píng)論