人生处处是惊喜,不是吗?

搜索 nihao-shijie 关注
nihao-shijie.lofter.com
“当一件事情足够重要时,即使目前结果并没有达到我的预期,我仍然需要坚持不懈地去做它!”

关于Mybatis动态代理中无法实现方法重载的原因分析

我们可以在官方文档中知道,Mybatis可以使用动态代理来进行mapper xml文件与接口的连接。

不过我们发现当我们在接口中出现重载的方法的时候,我们在相应的mapper文件中也会定义两个id一样的节点。

当我们启动项目的时候,就会发现项目运行会出现错误,导致项目无法运行。

那么为什么在mapper中定义两个或者多个重名方法节点会导致错误呢。这肯定和id的唯一性有关。

下面我们通过源码来尝试解释一下这个流程。

mybatis动态代理主要是使用SqlSessionFactoryBean(org.mybatis.spring.SqlSessionFactoryBean)类,我们会为这类注入我们的配置文件mapperLocations。

项目启动的时候会实例化这类,同时会调用buildSqlSessionFactory()来创建与数据库的连接工厂来维护我们的项目中用到的部分bean。

这个时候,mybatis会根据我们配置的xml(这里不是指单个mapper,而是根据我们的配置路径获取mapper集合(也可能是单个mapper),也就是mappers,多个路径会被加载多次,每每个路径下的如果有N个文件就会产生N个Resource)来分析我们配置的mappers。

因为对每一个mapper,我们会分析里面的节点,因为mapper是xml格式的嘛!所以还需要对节点进行迭代逐个分析

Iterator<XMLStatementBuilder> iter = incompleteStatements.iterator();

      while (iter.hasNext()) {

      try {

          iter.next().parseStatementNode();

          iter.remove();

      } catch (IncompleteElementException e) {

          // Statement is still missing a resource...

      }

  }

资源会被加载到xmlMapperBuilder对象中,同时xmlMapperBuilderparse()方法来分析我们的配置,分析的顺序是先分析ResultMap,再分析ChacheRef,最后分析Statements

现在因为我们项目中,有重载的方法,或者同一个DAO层下面会有两个以及多个相同名称的方法,虽然他们参数类型和参数个数不一样。

所以我们关于ResultMap结果集和ChacheRef缓存不是本次讨论重点,我们着重看Statements语句声明

parsePendingStatements()中,我们会对Statements进行分析,因为mapper会包含多个Statement会对每一个Statement进行处理。

parseStatementNode()中,我们会得到每一个声明语句的属性以及属性值,其中本次讨论的核心是id,所以我们只关心属性id。

我们会将每个Statement的属性值添加到builderAssistantMappedStatement对象中,这里面存放的就是一条条的声明语句。

在我们真正将声明语句添加到MappedStatement中,我们需要通过statementBuilderbuild()来构建MappedStatement对象。

在此之前,我们都不会去检查MappedStatement是否有重复的内容,以及如何去检查,都是在构建好MappedStatement对象之后处理的。

当我们构建好MappedStatement对象之后,我们才开始真正将MappedStatement对象通过put操作添加到configuration(全局配置对象)mappedStatements(这是一个map)中。而Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>(...);

并不是我们常见的HashMap,我们在深入看一下发现class StrictMap<V> extends HashMap<String, V> ,原来StrictMap继承了HashMap。

那我们使用的put是不是也是一样的呢?

结果是否定的!!!

public V put(String key, V value) {

      if (containsKey(key))    //这一句是核心

        throw new IllegalArgumentException(name + " already contains value for " + key);

     //此处省略...

      }

      return super.put(key, value);

    }

很明显,我们在put之前,做了一些检查,如果有重复的也就是id相同的声明语句,那么就会报错!


这就是为什么Mybatis动态代理中无法实现方法重载的原因。

评论(1)
热度(1)

© 你好-世界 | Powered by LOFTER