Mybatis源码剖析之插件Interceptor执行原理

mybatis通过插件 对(Executor、StatementHandler、ParameterHandler、ResultSetHandler) 这四个 核心对象创建代理进行拦截
对mybatis来说插件就是拦截器,用来增强核心对象的功能,增强功能本质上是借助于底层的 动态代理实现的,换句话说,MyBatis中的四大对象都是代理对象

不熟悉 Mybatis 执行流程的,请先阅读: Mybatis 执行流程

Mybatis核心对象介绍
MyBatis的主要的核心部件有以下几个:

Configuration 初始化基础配置,比如MyBatis的别名等,一些重要的类型对象,如,插件,映射器,ObjectFactory和typeHandler对象,MyBatis所有的配置信息都维持在Configuration对象之中

SqlSessionFactory SqlSession工厂

SqlSession 作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能

Executor MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护

StatementHandler 封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合。

ParameterHandler 负责对用户传递的参数转换成JDBC Statement 所需要的参数,

ResultSetHandler 负责将JDBC返回的ResultSet结果集对象转换成List类型的集合;

TypeHandler 负责java数据类型和jdbc数据类型之间的映射和转换

MappedStatement 维护了一条<select|update|delete|insert>节点的封装,

SqlSource 负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回

BoundSql 表示动态生成的SQL语句以及相应的参数信息

代理模式一般是专注一个类,或者某些类,进行增强,或者想在前后加点业务逻辑,那么就可以使用代理模式。
动态代理一般更加灵活,可以任意指定某些要代理的类,然后指定某些方法。
静态代理,一般是在静态代码块中,对某个类进行代理,然后通过代理对象来调用目标对象的方法。常用手段就是 委托,装饰,组合等。

代理模式,一般是聚焦局部的。模板方法模式,一般是聚焦整体,宏观。

模板方法模式,一般是在多态下继承关系上,在父类指定整体流程的执行步骤和骨架,然后制定抽象方法,先 “假设” 某些逻辑存在,把"填空"的抽象方法交给各子类进行实现。

框架通常会在提供扩展点,让核心流程不变的情况下,让用户自己定制化,从而达到灵活的目的。Mybatis 插件机制,亦如是也!

Mybatis 是通过JDK动态代理实现的,然后有些框架是通过装饰模式实现的。

下面是 插件机制的实现原理,首先是应用插件的4个地方,就是 4 大组件实例化的时候,遍历插件进行代理,然后把代理对象返回,这样就增强了。

配置插件,在配置文件中,通过标签,来配置插件, 或者 API的方法 Configuration#addInterceptor 来配置。

对应的 拦截器插件实现类上面一定要有@Intercepts注解,用来声明拦截器要拦截的方法。否则就直接抛异常。

    // Plugin#getSignatureMap 源码

    Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
    // issue #251
    if (interceptsAnnotation == null) {
   
   
      throw new PluginException(
          "No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());
    }

下面是 源码分析,全程代码注释:

首先是创建插件的实现,是在4大组件实例化的时候,用JDK动态代理的方式,生成的带有拦截器业务代码的 组件代理对象

public class Configuration {
   
   

  // 拦截器链,维护了一个List, 插件列表
  protected final InterceptorChain interceptorChain = new InterceptorChain();

  // 默认的 执行器类型
  protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;

  /**
   * Gets the interceptors.
   *
   * @return the interceptors
   * @since 3.2.2
   */
  public List<Interceptor> getInterceptors() {
   
   
    return interceptorChain.getInterceptors();
  }

  public void addInterceptor(Interceptor interceptor) {
   
   
    interceptorChain.addInterceptor(interceptor);
  }

  // 获取 DefaultSqlSession 的过程中,需要 实例化 4 大组件, 也正是拦截器要拦截的地方。
  // pluginAll 方法会遍历 插件列表,每当有一个符合条件插件,就生成一个代理,JDK的代理方式,
  // 代理对象是一层嵌套一层的,总是最后一个插件生成的代理类的invoke方法,总是最先执行。
  public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject,
      BoundSql boundSql) {
   
   
    ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement,
        parameterObject, boundSql);
    // 传入原始的 ParameterHandler 对象,吐出来一个 JDK 代理对象
    parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
    return parameterHandler;
  }

  public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds,
      ParameterHandler parameterHandler,
      ResultHandler resultHandler, BoundSql boundSql) {
   
   
    ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler,
        resultHandler, boundSql, rowBounds);
    // 传入原始的 ResultSetHandler 对象,吐出来一个 JDK 代理对象
    resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
    return resultSetHandler;
  }

  public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement,
      Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
   
   
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject,
        rowBounds, resultHandler, boundSql);
    // 传入原始的 StatementHandler 对象,吐出来一个 JDK 代理对象
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
  }

  public Executor newExecutor(Transaction transaction) {
   
   
    return newExecutor(transaction, defaultExecutorType);
  }

  public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
   
   
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
   
   
      executor = new BatchExecutor(this, transaction);
    } els
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值