zoukankan      html  css  js  c++  java
  • mybatis源码分析(5)-----拦截器的实现原理(动态代理+责任链)

    写在前面

      MyBatsi 的拦截器模式是基于代理的代理模式。并且myBatis 的插件开发也是以拦截器的形式集成到myBatis 当中。

      MyBatis 的拦截器已经插件是在org.apache.ibatis.plugin包下面。

      MyBatis拦截器可以拦截的类,Executor(执行器),ParameterHandler(参数处理器),ResultSetHandler(结果集处理器),StatementHandler(句处理器)。

    本文以Executor的插件为例子,来说明MyBatis 插件的工作原理

     1.首先分析 产生执行器Excutor 的代码

       通过interceptorChain的拦截器链,当一个执行器有过个拦截器,回产生拦截器链,也就是多重代理对象

       Configuration.java 文件
    //产生执行器 public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; //这句再做一下保护,囧,防止粗心大意的人将defaultExecutorType设成null? executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; //然后就是简单的3个分支,产生3种执行器BatchExecutor/ReuseExecutor/SimpleExecutor if (ExecutorType.BATCH == executorType) { executor = new BatchExecutor(this, transaction); } else if (ExecutorType.REUSE == executorType) { executor = new ReuseExecutor(this, transaction); } else { executor = new SimpleExecutor(this, transaction); } //如果要求缓存,生成另一种CachingExecutor(默认就是有缓存),装饰者模式,所以默认都是返回CachingExecutor if (cacheEnabled) { executor = new CachingExecutor(executor); } //此处调用插件,通过插件可以改变Executor行为 executor = (Executor) interceptorChain.pluginAll(executor); return executor; }

        Executor 执行器采用了模板方法模式。 

        Executor是执行器调度的核心。SqlSesson对外提供的api 其实就是 对于Executor 的调用(API-->SqlSesson-->Executor-->Statment-->DB)

      模板方法模式(解释):

         Executor 接口提供了query、update、commit、rollback 等方法。

         实现类BaseExecutor 给予基本的实现,在执行目标之前和之后 做了相关的处理(模板),且提供了实现具体操作的抽象方法。使得具体实现类SimpleExecutor、BatchExecutor、ReuseExecutor关注具体方法的实现。

         SimpleExecutor,BatchExecutor、ReuseExecutor 只需要实现自己的具体操作 doQuery、doUpdate、doCommit、doRollBack.

    Executor executor = new SimpleExecutor();  
    executor .query();

     2 其实Plugin采用了,插件,用的代理模式。自己实现了InvocationHandler接口,维护了目标类target和一个目标拦截器interceptor  

    public class Plugin implements InvocationHandler {
    
      private Object target;
      private Interceptor interceptor;
      private Map<Class<?>, Set<Method>> signatureMap;
    
      private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) {
        this.target = target;
        this.interceptor = interceptor;
        this.signatureMap = signatureMap;
      }
    
      public static Object wrap(Object target, Interceptor interceptor) {
        //取得签名Map
        Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
        //取得要改变行为的类(ParameterHandler|ResultSetHandler|StatementHandler|Executor)
        Class<?> type = target.getClass();
        //取得接口
        Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
        //产生代理
        if (interfaces.length > 0) {
          return Proxy.newProxyInstance(
              type.getClassLoader(),
              interfaces,
              new Plugin(target, interceptor, signatureMap));
        }
        return target;
      }
    
      @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)) {
            //调用Interceptor.intercept,也即插入了我们自己的逻辑
            return interceptor.intercept(new Invocation(target, method, args));
          }
          //最后还是执行原来逻辑
          return method.invoke(target, args);
        } catch (Exception e) {
          throw ExceptionUtil.unwrapThrowable(e);
        }
      }
    }

    myBatis 中用到的设计模式

    一、建造者模式

    BaseBuilder、XMLMapperBuilder、SQlSessionFactoryBuilder

    二、工厂方法

    SqlSessionFactory、TranscationFactory、MapperProxyFactory

    三、模板方法模式

    Executor、StatmentHandler

    四、动态代理

    Plugin、SqlSessionTemplate、MapperProxy

    五、责任链模式

    Interceptor、InterceptorChain

      

  • 相关阅读:
    VirtualBox下Ubuntu更改分辨率方法
    Asp.Net防止刷新重复提交数据小记
    耻辱名单新成员,腾讯QQ影音违反开源协议遭谴责
    赛门铁克BERS 2010新增Linux备份还原
    开源邮件服务解决方案 iRedMail0.6.0beta1 发布,支持 FreeBSD
    防止ASP.NET按钮多次提交代码
    与省局网站备案管理系统接口规范试行版文件下载地址
    2010预测:开源ERP难有大作为
    ASP.NET对IIS中的虚拟目录进行操作
    C#三种模拟自动登录和提交POST信息的实现方法
  • 原文地址:https://www.cnblogs.com/chihirotan/p/6679139.html
Copyright © 2011-2022 走看看