Configuration--mappers--XMLMapperBuilder.parse(三-8-2)

本文详细解析了MyBatis中XMLMapperBuilder的parse方法如何处理XML文件,并生成MappedStatement对象。通过分析bindMapperForNamespace及configurationElement方法,揭示了namespace对应Class的绑定过程以及mapper标签下的子标签解析流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇我们讲了ConfigurationaddMappers方法,可以看出,这个方法的最终目的,是将我们定义的mapper接口最终转化为MappedStatement,然后加入Configuration中,并且我们从上一篇文章中可以看出,即使我们是使用了class去配置mapper,也会去默认路径下加载xml文件.

本篇我们来看看当mapper标签加载的是一个xml文件时使用的XMLMapperBuilder.parse:

  public void parse() {
    // 看是否已经加载过该配置文件
    if (!configuration.isResourceLoaded(resource)) {
      // 解析mapper标签
      configurationElement(parser.evalNode("/mapper"));
      // 标识该xml文件已经被加载过
      configuration.addLoadedResource(resource);
      // 去加载对应的namespace对应的class
      bindMapperForNamespace();
    }

    // 这三个方法是重新加载一遍之前加载出错的标签
    parsePendingResultMaps();
    parsePendingChacheRefs();
    parsePendingStatements();
  }

我们先来看bindMapperForNamespace方法:

  // 在这个方法里,我们看到了熟悉的configuration.addMapper()方法,这说明在加载xml文件时,也会去解析一下namespace对应的class(如果该class存在的话)
  private void bindMapperForNamespace() {
    String namespace = builderAssistant.getCurrentNamespace();
    if (namespace != null) {
      Class<?> boundType = null;
      try {
        boundType = Resources.classForName(namespace);
      } catch (ClassNotFoundException e) {
        //ignore, bound type is not required
      }
      if (boundType != null) {
        if (!configuration.hasMapper(boundType)) {
          // Spring may not know the real resource name so we set a flag
          // to prevent loading again this resource from the mapper interface
          // look at MapperAnnotationBuilder#loadXmlResource
          configuration.addLoadedResource("namespace:" + namespace);
          configuration.addMapper(boundType);
        }
      }
    }
  }

接下来,我们再来看解析标签的configurationElement方法:

  // 从该方法中,我们可以看出,会逐步解析mapper标签下的子标签,具体解析过程,这里就不慢慢分析了,因为涉及到的细节过多,但是最终肯定是会生成一个MappedStatement的
  private void configurationElement(XNode context) {
    try {
      String namespace = context.getStringAttribute("namespace");
      if (namespace.equals("")) {
          throw new BuilderException("Mapper's namespace cannot be empty");
      }
      builderAssistant.setCurrentNamespace(namespace);
      cacheRefElement(context.evalNode("cache-ref"));
      cacheElement(context.evalNode("cache"));
      parameterMapElement(context.evalNodes("/mapper/parameterMap"));
      resultMapElements(context.evalNodes("/mapper/resultMap"));
      sqlElement(context.evalNodes("/mapper/sql"));
      buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
    }
  }

至此,我们Configuration就分析完了,也成功的构建出了DefaultSqlSessionFactory,因为最终DefaultSqlSessionFactory中就只有一个Configuration:

  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

由于最后的mapper解析过程实在是复杂,所以本系列文章就简化了,之后如果有机会,博主会单开章节来写.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值