resultMap的解析
书接上回,mybatis对于<resultMap></resultMap>
标签解析的方法入口为:
resultMapElements(List list)
根据mybatis-3-mapper.dtd文件中对于resultMap的定义可知,一个mapper节点内可以定义任意多个resultMap节点,所以resultMapElements方法会遍历所有的resultMap进行解析,代码如下:
private void resultMapElements(List<XNode> list) {
for (XNode resultMapNode : list) {
try {
resultMapElement(resultMapNode);
} catch (IncompleteElementException e) {
// ignore, it will be retried
}
}
}
resultMapElement(XNode)
调用重载方法,三个参数的resultMapElement方法主要用于后续递归调用,所以这里单参数的resultMapElement方法更像是一个“桥接”方法。
private ResultMap resultMapElement(XNode resultMapNode) {
return resultMapElement(resultMapNode, Collections.emptyList(), null);
}
resultMapElement(XNod, List, Class)方法
resultMapElement方法会为<resultMap></resultMap>
中配置的每一个或标签都创建一个ResultMapping对象,并将其保存在一个集合中,最后传递给ResultMapResolver对象进行解析。
private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings, Class<?> enclosingType) {
ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier());
//因为<resultMap/>标签的配置存在嵌套的情况,所以在代码处理嵌套情况的时候一定会使用递归,
//这里获取默认值的逻辑主要是为了处理<resultMap/>嵌套<resultMap/>的情况
String type = resultMapNode.getStringAttribute("type",
resultMapNode.getStringAttribute("ofType",
resultMapNode.getStringAttribute("resultType",
resultMapNode.getStringAttribute("javaType"))));
//解析type属性所配置的类
Class<?> typeClass = resolveClass(type);
if (typeClass == null) {
typeClass = inheritEnclosingType(resultMapNode, enclosingType);
}
Discriminator discriminator = null; //resultMappings集合中维护了当前<resultMap/>中所有的映射关系
List<ResultMapping> resultMappings = new ArrayList<>(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<>();
if ("id".equals(resultChild.getName())) {
flags.add(ResultFlag.ID);
}
resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
}
}
//获取resultMap节点配置的ID
//getValueBasedIdentifier()方法返回的格式为 类型1[ID1]_类型2[ID2]......
String id = resultMapNode.getStringAttribute("id",
resultMapNode.getValueBasedIdentifier());
//获取resultMap节点配置的继承关系
String extend = resultMapNode.getStringAttribute("extends");
//获取是否开启自动映射配置
Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");
//创建ResultMap解析器实例
ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
try {
//将具体的解析任务委派给MapperBuilderAssistant的实例
return resultMapResolver.resolve();
} catch (IncompleteElementException e) {
configuration.addIncompleteResultMap(resultMapResolver);
throw e;
}
}
解析<constructor/>
processConstructorElement方法对构造函数节点中的ID进行了特殊的标识,便于在后续的解析中区分对id和idArg进行区分,如下图所示,:
private void processConstructorElement(XNode resultChild, Class<?> resultType, List<ResultMapping> resultMappings) {
List