【Mybatis】Mybatis源码之resultMap标签解析

1,390 阅读2分钟

这是我参与8月更文挑战的第19天,活动详情查看:8月更文挑战

时序图

sequenceDiagram
participant A as XMLMapperBuilder
participant B as ResultMapResolver
participant C as MapperBuilderAssistant
participant D as ResultMap.Builder

A ->> A : resultMapElements
A ->> A : resultMapElement
A ->> B : resolve
B ->> C : addResultMap
C ->> D : build
D -->> C : ResultMap

详细步骤

XMLMapperBuilder#configurationElement

/**
 * 解析映射文件的下层节点
 * @param context 映射文件根节点
 */
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"));
        // 处理各个数据库操作语句
        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);
    }
}

XMLMapperBuilder#resultMapElement

private void resultMapElements(List<XNode> list) throws Exception {
    // 遍历
    for (XNode resultMapNode : list) {
        try {
            // 处理单个resultMap标签
            resultMapElement(resultMapNode);
        } catch (IncompleteElementException e) {
            // ignore, it will be retried
        }
    }
}

private ResultMap resultMapElement(XNode resultMapNode) throws Exception {
    return resultMapElement(resultMapNode, Collections.emptyList(), null);
}

/**
 * 兼容处理
 */
private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings, Class<?> enclosingType) throws Exception {
    ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier());
    /**
     * 所有类型的resultMap相关类型标签都可处理
     * 针对不同类型的resultMap标签,通过不同的属性来获取type
     */
    String type = resultMapNode.getStringAttribute("type",
            resultMapNode.getStringAttribute("ofType",
                    resultMapNode.getStringAttribute("resultType",
                            resultMapNode.getStringAttribute("javaType"))));
    // 通过别名来解析获取typeClass
    Class<?> typeClass = resolveClass(type);
    // 获取继承的typeClass
    if (typeClass == null) {
        typeClass = inheritEnclosingType(resultMapNode, enclosingType);
    }
    Discriminator discriminator = null;
    List<ResultMapping> resultMappings = new ArrayList<>();
    //将已解析的标签放入resultMappings
    resultMappings.addAll(additionalResultMappings);
    List<XNode> resultChildren = resultMapNode.getChildren();
    // 解析resultMap标签下的所有子标签
    for (XNode resultChild : resultChildren) {
        // 解析构造标签constructor
        if ("constructor".equals(resultChild.getName())) {
            processConstructorElement(resultChild, typeClass, resultMappings);
        }
        // 解析discriminator鉴别器标签
        else if ("discriminator".equals(resultChild.getName())) {
            discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
        }
        // 解析普通标签
        else {
            List<ResultFlag> flags = new ArrayList<>();
            if ("id".equals(resultChild.getName())) {
                flags.add(ResultFlag.ID);
            }
            // 构建ResultMapping对象(若未指定javaType,则根据属性的set方法参数类型来设置javaType,并获取对应的TypeHandler),并添加到容器中
            resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
        }
    }
    String id = resultMapNode.getStringAttribute("id",
            resultMapNode.getValueBasedIdentifier());
    String extend = resultMapNode.getStringAttribute("extends");
    Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");
    // 创建解析器
    ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
    try {
        // 解析
        return resultMapResolver.resolve();
    } catch (IncompleteElementException e) {
        configuration.addIncompleteResultMap(resultMapResolver);
        throw e;
    }
}

ResultMapResolver#resolve

/**
 * 完成 ResultMap 的继承关系解析,并将解析的结果放入Configuration中的resultMaps中
 * @return
 */
public ResultMap resolve() {
    return assistant.addResultMap(this.id, this.type, this.extend, this.discriminator, this.resultMappings, this.autoMapping);
}

MapperBuilderAssistant#addResultMap

/**
 * 创建结果映射对象
 * @param id 输入参数参照 ResultMapResolver 属性
 * @return ResultMap对象
 */
public ResultMap addResultMap(
        String id,
        Class<?> type,
        String extend,
        Discriminator discriminator,
        List<ResultMapping> resultMappings,
        Boolean autoMapping) {
    id = applyCurrentNamespace(id, false);
    extend = applyCurrentNamespace(extend, true);

    // 解析ResultMap的继承关系
    if (extend != null) {
        // 判断configuration对象中是否存在extend指向的ResultMap,如果没有,则抛出异常,在后续操作中再次对当前ResultMap进行解析处理
        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<>(resultMap.getResultMappings());
        // 删除父类映射中在子类映射中已经存在的属性,从而使用子类映射覆盖父类映射
        extendedResultMappings.removeAll(resultMappings);
        // Remove parent constructor if this resultMap declares a constructor.
        // 如果当前子类ResultMap设置有构建器,则移除父级构建器
        boolean declaresConstructor = false;
        for (ResultMapping resultMapping : resultMappings) {
            if (resultMapping.getFlags().contains(ResultFlag.CONSTRUCTOR)) {
                declaresConstructor = true;
                break;
            }
        }
        if (declaresConstructor) {
            extendedResultMappings.removeIf(resultMapping -> resultMapping.getFlags().contains(ResultFlag.CONSTRUCTOR));
        }
        // 最终从父级继承而来的所有属性映射
        resultMappings.addAll(extendedResultMappings);
    }
    // 创建当前的ResultMap
    ResultMap resultMap = new ResultMap.Builder(configuration, id, type, resultMappings, autoMapping)
            .discriminator(discriminator)
            .build();
    // 将当前的ResultMap加入configuration
    configuration.addResultMap(resultMap);
    return resultMap;
}

ResultMap#build

public ResultMap build() {
    if (resultMap.id == null) {
        throw new IllegalArgumentException("ResultMaps must have an id");
    }
    resultMap.mappedColumns = new HashSet<>();
    resultMap.mappedProperties = new HashSet<>();
    resultMap.idResultMappings = new ArrayList<>();
    resultMap.constructorResultMappings = new ArrayList<>();
    resultMap.propertyResultMappings = new ArrayList<>();
    final List<String> constructorArgNames = new ArrayList<>();
    for (ResultMapping resultMapping : resultMap.resultMappings) {
        resultMap.hasNestedQueries = resultMap.hasNestedQueries || resultMapping.getNestedQueryId() != null;
        resultMap.hasNestedResultMaps = resultMap.hasNestedResultMaps || (resultMapping.getNestedResultMapId() != null && resultMapping.getResultSet() == null);
        final String column = resultMapping.getColumn();
        if (column != null) {
            // 在已映射的列中添加当前列,名称转换为全大写
            resultMap.mappedColumns.add(column.toUpperCase(Locale.ENGLISH));
        } else if (resultMapping.isCompositeResult()) {
            for (ResultMapping compositeResultMapping : resultMapping.getComposites()) {
                final String compositeColumn = compositeResultMapping.getColumn();
                if (compositeColumn != null) {
                    resultMap.mappedColumns.add(compositeColumn.toUpperCase(Locale.ENGLISH));
                }
            }
        }
        final String property = resultMapping.getProperty();
        if (property != null) {
            // 在已映射的属性中添加当前属性
            resultMap.mappedProperties.add(property);
        }
        // 如果是constructor标签下的映射关系,则放入constructorResultMappings中
        if (resultMapping.getFlags().contains(ResultFlag.CONSTRUCTOR)) {
            resultMap.constructorResultMappings.add(resultMapping);
            if (resultMapping.getProperty() != null) {
                // 如果映射关系中name属性不为空,则放入constructorArgNames中
                constructorArgNames.add(resultMapping.getProperty());
            }
        } else {
            resultMap.propertyResultMappings.add(resultMapping);
        }
        // 将id放入idResultMappings中(id标签和idArg标签)
        if (resultMapping.getFlags().contains(ResultFlag.ID)) {
            resultMap.idResultMappings.add(resultMapping);
        }
    }
    // 如果idResultMappings为空,则将所有映射放入
    if (resultMap.idResultMappings.isEmpty()) {
        resultMap.idResultMappings.addAll(resultMap.resultMappings);
    }
    // 当constructorArgNames不为空时
    if (!constructorArgNames.isEmpty()) {
        // 根据配置的参数映射获取对应构造方法中的参数列表
        final List<String> actualArgNames = argNamesOfMatchingConstructor(constructorArgNames);
        if (actualArgNames == null) {
            throw new BuilderException("Error in result map '" + resultMap.id
                    + "'. Failed to find a constructor in '"
                    + resultMap.getType().getName() + "' by arg names " + constructorArgNames
                    + ". There might be more info in debug log.");
        }
        // 将映射关系constructorResultMappings按照获取的参数顺序排序
        resultMap.constructorResultMappings.sort((o1, o2) -> {
            int paramIdx1 = actualArgNames.indexOf(o1.getProperty());
            int paramIdx2 = actualArgNames.indexOf(o2.getProperty());
            return paramIdx1 - paramIdx2;
        });
    }
    // lock down collections
    // 锁定映射的结果集
    resultMap.resultMappings = Collections.unmodifiableList(resultMap.resultMappings);
    resultMap.idResultMappings = Collections.unmodifiableList(resultMap.idResultMappings);
    resultMap.constructorResultMappings = Collections.unmodifiableList(resultMap.constructorResultMappings);
    resultMap.propertyResultMappings = Collections.unmodifiableList(resultMap.propertyResultMappings);
    resultMap.mappedColumns = Collections.unmodifiableSet(resultMap.mappedColumns);
    return resultMap;
}

以上便是Mybatis解析resultMap标签的过程。