Mybatis学习系列(四):源码解析—解析mapper

上一篇主要是介绍了mybatis-config.xml配置文件的解析,里面只是简单的列了一下mapper的解析,由于这个是比较核心和重要的,这里我们将进行详细的解析:

private void mapperElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        if ("package".equals(child.getName())) {
          String mapperPackage = child.getStringAttribute("name");
          configuration.addMappers(mapperPackage);
        } else {
          String resource = child.getStringAttribute("resource");
          String url = child.getStringAttribute("url");
          String mapperClass = child.getStringAttribute("class");
          if (resource != null && url == null && mapperClass == null) {
            ErrorContext.instance().resource(resource);
            InputStream inputStream = Resources.getResourceAsStream(resource);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
            mapperParser.parse();
          } else if (resource == null && url != null && mapperClass == null) {
            ErrorContext.instance().resource(url);
            InputStream inputStream = Resources.getUrlAsStream(url);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
            mapperParser.parse();
          } else if (resource == null && url == null && mapperClass != null) {
            Class<?> mapperInterface = Resources.classForName(mapperClass);
            configuration.addMapper(mapperInterface);
          } else {
            throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
          }
        }
      }
    }
  }

1.package维度的解析

//获取到整体的包路径
String mapperPackage = child.getStringAttribute("name");
//调用configuration的方法进行解析和添加Mappers
configuration.addMappers(mapperPackage);

//这里主要是调用了mapperRegistry的add方法
public void addMappers(String packageName) {
    mapperRegistry.addMappers(packageName);
  }

//这里是添加包下的所有mapper类
public void addMappers(String packageName, Class<?> superType) {
    //这里通过反射拿到包下的所有类的class路径
    ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
    resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
    Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
    //循环去解析每个对象
    for (Class<?> mapperClass : mapperSet) {
      addMapper(mapperClass);
    }
  }

1.1我们详细看一下,单个mapper的解析

public <T> void addMapper(Class<T> type) {
    //当前传入的class必须是接口
    if (type.isInterface()) {
      //这里判断每一个mapper只能被解析一次
      if (hasMapper(type)) {
        throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
      }
      boolean loadCompleted = false;
      try {
        //这里生成MapperProxyFactory对象并且保存到内存map中
        //key是当前的class类型 values是MapperProxyFactory对象
        knownMappers.put(type, new MapperProxyFactory<T>(type));
        //这里会初始化MapperAnnotationBuilder对象
        //进行mapper里的注解的解析(select,insert,update等)
        MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
        parser.parse();
        loadCompleted = true;
      } finally {
        if (!loadCompleted) {
          knownMappers.remove(type);
        }
      }
    }
  }

从上面已经拿到了解析的对象,下面就是开始对mapper进行解析了

public void parse() {
    String resource = type.toString();
    //每个mapper文件只能被解析一次
    if (!configuration.isResourceLoaded(resource)) {
      //这里解析mapper文件对应的xml文件
      loadXmlResource();
      //记录解析过的文件
      configuration.addLoadedResource(resource);
      //设置当前的Namespace
      assistant.setCurrentNamespace(type.getName());
      //解析缓存
      parseCache();
      parseCacheRef();
      //解析当前mapper的方法 生成对应的MappedStatement对象
      Method[] methods = type.getMethods();
      for (Method method : methods) {
        try {
          // issue #237
          if (!method.isBridge()) {
            parseStatement(method);
          }
        } catch (IncompleteElementException e) {
          configuration.addIncompleteMethod(new MethodResolver(this, method));
        }
      }
    }
    //对解析失败的方法,重新进行解析一次
    parsePendingMethods();
  }

1.1.1首先来看一下解析对应的mapper.xml文件

private void loadXmlResource() {
    //这里依然是判断一下,当前文件是否已经被解析过
    if (!configuration.isResourceLoaded("namespace:" + type.getName())) {
      //组装xml文件路径
      String xmlResource = type.getName().replace('.', '/') + ".xml";
      InputStream inputStream = null;
      try {
        inputStream = Resources.getResourceAsStream(type.getClassLoader(), xmlResource);
      } catch (IOException e) {
        // ignore, resource is not required
      }
      if (inputStream != null) {
        XMLMapperBuilder xmlParser = new XMLMapperBuilder(inputStream, assistant.getConfiguration(), xmlResource, configuration.getSqlFragments(), type.getName());
        //解析xml文件
        xmlParser.parse();
      }
    }
  }

解析xml文件

public void parse() {
    if (!configuration.isResourceLoaded(resource)) {
      //解析/mapper标签
      configurationElement(parser.evalNode("/mapper"));
      configuration.addLoadedResource(resource);
      //绑定mapper和namespace
      bindMapperForNamespace();
    }
    //解析resultMap
    parsePendingResultMaps();
    //解析缓存
    parsePendingCacheRefs();
    //解析绑定Statement
    parsePendingStatements();
  }

1.1.1.1解析mapper标签

private void configurationElement(XNode context) {
    try {
      //获取namespace
      String namespace = context.getStringAttribute("namespace");
      if (namespace == null || 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"));
      //解析公共sql
      sqlElement(context.evalNodes("/mapper/sql"));
      //解析(增删改查)SQL
      buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
    }
  }

1.1.1.1.1我们看下这里的解析入参映射

private void parameterMapElement(List<XNode> list) throws Exception {
    //循环所有的入参定义
    for (XNode parameterMapNode : list) {
      //定义的ID
      String id = parameterMapNode.getStringAttribute("id");
      //对应的对象类型
      String type = parameterMapNode.getStringAttribute("type");
      //获取当前对象class
      Class<?> parameterClass = resolveClass(type);
      //解析遍历当前定义的所有的参数字段
      List<XNode> parameterNodes = parameterMapNode.evalNodes("parameter");
      List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>();
      for (XNode parameterNode : parameterNodes) {
        //参数字段
        String property = parameterNode.getStringAttribute("property");
        //对应的java类型
        String javaType = parameterNode.getStringAttribute("javaType");
        //对应的数据库类中
        String jdbcType = parameterNode.getStringAttribute("jdbcType");
        //返回的map
        String resultMap = parameterNode.getStringAttribute("resultMap");
        String mode = parameterNode.getStringAttribute("mode");
        //类型转换的转换器
        String typeHandler = parameterNode.getStringAttribute("typeHandler");
        Integer numericScale = parameterNode.getIntAttribute("numericScale");
        ParameterMode modeEnum = resolveParameterMode(mode);
        Class<?> javaTypeClass = resolveClass(javaType);
        JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
        @SuppressWarnings("unchecked")
        Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
        //绑定关联关系
        ParameterMapping parameterMapping = builderAssistant.buildParameterMapping(parameterClass, property, javaTypeClass, jdbcTypeEnum, resultMap, modeEnum, typeHandlerClass, numericScale);
        parameterMappings.add(parameterMapping);
      }
      builderAssistant.addParameterMap(id, parameterClass, parameterMappings);
    }
  }

1.1.1.1.2解析结果映射

private void resultMapElements(List<XNode> list) throws Exception {
    //循环所有的映射设定
    for (XNode resultMapNode : list) {
      try {
        //解析单个映射设定
        resultMapElement(resultMapNode);
      } catch (IncompleteElementException e) {
        // ignore, it will be retried
      }
    }
  }

private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings) throws Exception {
    ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier());
    //获取ID
    String id = resultMapNode.getStringAttribute("id",
        resultMapNode.getValueBasedIdentifier());
    //获取返回类型
    String type = resultMapNode.getStringAttribute("type",
        resultMapNode.getStringAttribute("ofType",
            resultMapNode.getStringAttribute("resultType",
                resultMapNode.getStringAttribute("javaType"))));
    String extend = resultMapNode.getStringAttribute("extends");
    Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");
    Class<?> typeClass = resolveClass(type);
    Discriminator discriminator = null;
    List<ResultMapping> resultMappings = new ArrayList<ResultMapping>();
    resultMappings.addAll(additionalResultMappings);
    List<XNode> resultChildren = resultMapNode.getChildren();
    //解析所有字段
    for (XNode resultChild : resultChildren) {
      //如果是构造方法形式的
      if ("constructor".equals(resultChild.getName())) {
        processConstructorElement(resultChild, typeClass, resultMappings);
      } else if ("discriminator".equals(resultChild.getName())) {
        discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
      } else {
        List<ResultFlag> flags = new ArrayList<ResultFlag>();
        //如果是主键 多了这个操作
        if ("id".equals(resultChild.getName())) {
          flags.add(ResultFlag.ID);
        }
        //组装ResultMapping关系
        resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
      }
    }
    //组装处理对象
    ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
    try {
      //进行类型转换处理
      return resultMapResolver.resolve();
    } catch (IncompleteElementException  e) {
      configuration.addIncompleteResultMap(resultMapResolver);
      throw e;
    }
  }

类型转换处理  最终其实是保存到configuration的ResultMap中

public ResultMap resolve() {
    //调用MapperBuilderAssistant方法
    return assistant.addResultMap(this.id, this.type, this.extend, this.discriminator, this.resultMappings, this.autoMapping);
  }


public ResultMap addResultMap(
      String id,
      Class<?> type,
      String extend,
      Discriminator discriminator,
      List<ResultMapping> resultMappings,
      Boolean autoMapping) {
    //获取当前定义的ID
    id = applyCurrentNamespace(id, false);
    //获取引入的其他定义的ID
    extend = applyCurrentNamespace(extend, true);

    //引入的不为空
    if (extend != null) {
      if (!configuration.hasResultMap(extend)) {
        throw new IncompleteElementException("Could not find a parent resultmap with id '" + extend + "'");
      }
      //拿到引入解析后的ResultMap映射关系
      ResultMap resultMap = configuration.getResultMap(extend);
      List<ResultMapping> extendedResultMappings = new ArrayList<ResultMapping>(resultMap.getResultMappings());
      //引入的映射关系  删除掉当前ID下的映射关系
      extendedResultMappings.removeAll(resultMappings);
      //如果当前ID下配置的是构造方法类型的 删除引入里面的构造方法的映射
      boolean declaresConstructor = false;
      for (ResultMapping resultMapping : resultMappings) {
        if (resultMapping.getFlags().contains(ResultFlag.CONSTRUCTOR)) {
          declaresConstructor = true;
          break;
        }
      }
      if (declaresConstructor) {
        Iterator<ResultMapping> extendedResultMappingsIter = extendedResultMappings.iterator();
        while (extendedResultMappingsIter.hasNext()) {
          if (extendedResultMappingsIter.next().getFlags().contains(ResultFlag.CONSTRUCTOR)) {
            extendedResultMappingsIter.remove();
          }
        }
      }
      //把引入的映射关系添加到当前的映射关系里
      resultMappings.addAll(extendedResultMappings);
    }
    //组装型的映射关系对象 添加到configuration中
    ResultMap resultMap = new ResultMap.Builder(configuration, id, type, resultMappings, autoMapping)
        .discriminator(discriminator)
        .build();
    configuration.addResultMap(resultMap);
    return resultMap;
  }

1.1.1.1.3解析公共sql

private void sqlElement(List<XNode> list) throws Exception {
    //如果有DatabaseId 先解析一遍SQL
    if (configuration.getDatabaseId() != null) {
      sqlElement(list, configuration.getDatabaseId());
    }
    sqlElement(list, null);
  }

private void sqlElement(List<XNode> list, String requiredDatabaseId) throws Exception {
    //循环所有的SQL定义
    for (XNode context : list) {
      String databaseId = context.getStringAttribute("databaseId");
      //获取当前定义的ID
      String id = context.getStringAttribute("id");
      id = builderAssistant.applyCurrentNamespace(id, false);
      if (databaseIdMatchesCurrent(id, databaseId, requiredDatabaseId)) {
        //这里比较简单  就是保存ID和内容的映射关系
        sqlFragments.put(id, context);
      }
    }
  }

1.1.1.1.4解析(增删改查)SQL

private void buildStatementFromContext(List<XNode> list) {
    if (configuration.getDatabaseId() != null) {
      buildStatementFromContext(list, configuration.getDatabaseId());
    }
    buildStatementFromContext(list, null);
  }

private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
    //循环所有的sql定义
    for (XNode context : list) {
      //组装解析器
      final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
      try {
        //解析sql定义
        statementParser.parseStatementNode();
      } catch (IncompleteElementException e) {
        configuration.addIncompleteStatement(statementParser);
      }
    }
  }

解析每一个单独的SQL定义

public void parseStatementNode() {
    //获取当前sql的定义ID
    String id = context.getStringAttribute("id");
    String databaseId = context.getStringAttribute("databaseId");

    if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
      return;
    }
    //获取一些配置的参数  包括入参,出参等
    Integer fetchSize = context.getIntAttribute("fetchSize");
    Integer timeout = context.getIntAttribute("timeout");
    String parameterMap = context.getStringAttribute("parameterMap");
    String parameterType = context.getStringAttribute("parameterType");
    Class<?> parameterTypeClass = resolveClass(parameterType);
    String resultMap = context.getStringAttribute("resultMap");
    String resultType = context.getStringAttribute("resultType");
    String lang = context.getStringAttribute("lang");
    LanguageDriver langDriver = getLanguageDriver(lang);

    Class<?> resultTypeClass = resolveClass(resultType);
    String resultSetType = context.getStringAttribute("resultSetType");
    StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
    ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);

    //获取sql的类型(增删改查)
    String nodeName = context.getNode().getNodeName();
    SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
    boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
    boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
    boolean useCache = context.getBooleanAttribute("useCache", isSelect);
    boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);

    //如果包含include也就是引入了其他的定义(公共SQL)
    XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
    includeParser.applyIncludes(context.getNode());

    // 解析selectKey 标签
    processSelectKeyNodes(id, parameterTypeClass, langDriver);
    
    // Parse the SQL (pre: <selectKey> and <include> were parsed and removed)
    SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
    String resultSets = context.getStringAttribute("resultSets");
    String keyProperty = context.getStringAttribute("keyProperty");
    String keyColumn = context.getStringAttribute("keyColumn");
    KeyGenerator keyGenerator;
    String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
    keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
    if (configuration.hasKeyGenerator(keyStatementId)) {
      keyGenerator = configuration.getKeyGenerator(keyStatementId);
    } else {
      keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
          configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
          ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
    }
    //创建MappedStatement
    builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
        fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
        resultSetTypeEnum, flushCache, useCache, resultOrdered, 
        keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
  }

创建MappedStatement:调用的是MapperBuilderAssistant的方法

public MappedStatement addMappedStatement(
      String id,
      SqlSource sqlSource,
      StatementType statementType,
      SqlCommandType sqlCommandType,
      Integer fetchSize,
      Integer timeout,
      String parameterMap,
      Class<?> parameterType,
      String resultMap,
      Class<?> resultType,
      ResultSetType resultSetType,
      boolean flushCache,
      boolean useCache,
      boolean resultOrdered,
      KeyGenerator keyGenerator,
      String keyProperty,
      String keyColumn,
      String databaseId,
      LanguageDriver lang,
      String resultSets) {

    if (unresolvedCacheRef) {
      throw new IncompleteElementException("Cache-ref not yet resolved");
    }
    //生成新的ID 为namespace.配置的ID
    id = applyCurrentNamespace(id, false);
    boolean isSelect = sqlCommandType == SqlCommandType.SELECT;

    MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)
        .resource(resource)
        .fetchSize(fetchSize)
        .timeout(timeout)
        .statementType(statementType)
        .keyGenerator(keyGenerator)
        .keyProperty(keyProperty)
        .keyColumn(keyColumn)
        .databaseId(databaseId)
        .lang(lang)
        .resultOrdered(resultOrdered)
        .resultSets(resultSets)
        .resultMaps(getStatementResultMaps(resultMap, resultType, id))
        .resultSetType(resultSetType)
        .flushCacheRequired(valueOrDefault(flushCache, !isSelect))
        .useCache(valueOrDefault(useCache, isSelect))
        .cache(currentCache);

    ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);
    if (statementParameterMap != null) {
      statementBuilder.parameterMap(statementParameterMap);
    }
    //创建MappedStatement 
    MappedStatement statement = statementBuilder.build();
    //加入到configuration中的map里 以ID为key MappedStatement 为值
    configuration.addMappedStatement(statement);
    return statement;
  }

1.1.1.2绑定mapper和namespace,这里最终还是走到了configuration.addMapper(boundType),也就是我们上面的1.1

private void bindMapperForNamespace() {
    //获取当前的namespace
    String namespace = builderAssistant.getCurrentNamespace();
    if (namespace != null) {
      //转换成class对象
      Class<?> boundType = null;
      try {
        boundType = Resources.classForName(namespace);
      } catch (ClassNotFoundException e) {
        //ignore, bound type is not required
      }
      if (boundType != null) {
        //当前mapper是否解析过
        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);
          //解析mapper添加到configuration中
          configuration.addMapper(boundType);
        }
      }
    }
  }

2.resource和url维度的解析:最终走到的是XMLMapperBuilder 的parse()方法,也就是我们上面的1.1.1的第二段代码

if (resource != null && url == null && mapperClass == null) {
            ErrorContext.instance().resource(resource);
            //解析resource 配置的路径xml
            InputStream inputStream = Resources.getResourceAsStream(resource);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
            mapperParser.parse();
          } else if (resource == null && url != null && mapperClass == null) {
            //解析url 配置的路径xml
            ErrorContext.instance().resource(url);
            InputStream inputStream = Resources.getUrlAsStream(url);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
            mapperParser.parse();
          }

3.单个mapper配置维度解析:调用的还是我们的上面的1.1步奏

else if (resource == null && url == null && mapperClass != null) {
            Class<?> mapperInterface = Resources.classForName(mapperClass);
            configuration.addMapper(mapperInterface);
          }

到这里mapper解析就完成了,最终把每个mapper类中的方法生成了一个个的MappedStatement 对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值