上一篇文章已经分析了解析 constructor 节点的方法,其他的节点最后基本上都是生成了 ResultMapping,discriminator 的解析就不分析了,这个 discriminator 节点主要是结果值来决定使用哪个结果映射。

最后是通过了 ResultMapResolver 来解析 ResultMapping 最后生成 ResultMap。

ResultMapResolver 分析

先来看一下 XMLMapperBuilder 的 resultMapElement 方法:

1
2
ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
return resultMapResolver.resolve();

上面代码上来看就是把上面解析出来的参数传递到 ResultMapResolver 的构造方法当中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ResultMapResolver {
private final MapperBuilderAssistant assistant;
private String id;//resultMap 节点属性 id
private Class<?> type;//resultMap 节点属性 type
private String extend;//resultMap 节点属性 extend
private Discriminator discriminator;
private List<ResultMapping> resultMappings;//解析出来的 resultMappings
private Boolean autoMapping;//resultMap 节点属性 autoMapping

public ResultMapResolver(MapperBuilderAssistant assistant, String id, Class<?> type, String extend, Discriminator discriminator, List<ResultMapping> resultMappings, Boolean autoMapping) {
this.assistant = assistant;
this.id = id;
this.type = type;
this.extend = extend;
this.discriminator = discriminator;
this.resultMappings = resultMappings;
this.autoMapping = autoMapping;
}
}

再来看 resolve 方法:

1
2
3
public ResultMap resolve() {
return assistant.addResultMap(this.id, this.type, this.extend, this.discriminator, this.resultMappings, this.autoMapping);
}

实际的生成 ResultMap 工作是在 MapperBuilderAssistant 当中进行的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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.Builder resultMapBuilder = new ResultMap.Builder(configuration, id, type, resultMappings, autoMapping);
if (extend != null) {
if (!configuration.hasResultMap(extend)) {
throw new IncompleteElementException("Could not find a parent resultmap with id '" + extend + "'");
}
ResultMap resultMap = configuration.getResultMap(extend);
List<ResultMapping> extendedResultMappings = new ArrayList<ResultMapping>(resultMap.getResultMappings());
extendedResultMappings.removeAll(resultMappings);
// Remove parent constructor if this resultMap declares a constructor.
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);
}
resultMapBuilder.discriminator(discriminator);
ResultMap resultMap = resultMapBuilder.build();
configuration.addResultMap(resultMap);
return resultMap;
}
  1. 首先根据 resultMap 的 id 生产全路径的 id,前缀是 namespace + ‘.’ + id
  2. 如果 resultMap 有 extend 生成 extend 的全路径字符串
  3. 创建 ResultMap.Builder 的对象实例
  4. 如果 extend 不是 null ,那么处理继承的 ResultMap
  5. 通过 builder 生成 ResultMap,并且添加到 configuration 当中去

下面详细的分析 extend 不是 null 的情况:

  1. 先从 configuration 当中获取继承的 ResultMap
  2. 然后把依赖的 resultMappings 去掉当前 resultMappings 重复属性的 resultMapping。
  3. 然后判断依赖的 resultMappings 当中是否存在构造方法 flag
  4. 如果存在构造方法 flag,则把这个构造方法的 ResultMapping 移除掉

接下继续分析 resultMapBuilder.build(); 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public ResultMap build() {
if (resultMap.id == null) {
throw new IllegalArgumentException("ResultMaps must have an id");
}
resultMap.mappedColumns = new HashSet<String>();
resultMap.idResultMappings = new ArrayList<ResultMapping>();
resultMap.constructorResultMappings = new ArrayList<ResultMapping>();
resultMap.propertyResultMappings = new ArrayList<ResultMapping>();
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));
}
}
}
if (resultMapping.getFlags().contains(ResultFlag.CONSTRUCTOR)) {
resultMap.constructorResultMappings.add(resultMapping);
} else {
resultMap.propertyResultMappings.add(resultMapping);
}
if (resultMapping.getFlags().contains(ResultFlag.ID)) {
resultMap.idResultMappings.add(resultMapping);
}
}
if (resultMap.idResultMappings.isEmpty()) {
resultMap.idResultMappings.addAll(resultMap.resultMappings);
}
// 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;
}
}

// 下面是 ResultMap 的属性
public class ResultMap {
private String id;
private Class<?> type;
private List<ResultMapping> resultMappings;//全部的resultMappings
private List<ResultMapping> idResultMappings;//id的 resultMappings
private List<ResultMapping> constructorResultMappings;//构造方法的 resultMappings
private List<ResultMapping> propertyResultMappings;// 属性的 resultMappings
private Set<String> mappedColumns;
private Discriminator discriminator;
private boolean hasNestedResultMaps;
private boolean hasNestedQueries;
private Boolean autoMapping;
}

上面代码做了如下操作:

  1. 先给 reusltMap 的属性(mappedColumns、idResultMappings、constructorResultMappings、propertyResultMappings)设置初始值。
  2. 循环全部的 resultMappings,如果其中任何一个 resultMapping 包含了 hasNestedQueries 那么 hasNestedQueries 属性就是 true,hasNestedResultMaps 同理。
  3. 在循环中把每个 resultMapping 的 column 属性都转换成大写放到 mappedColumns 当中
  4. 根据 flag 把 全部的resultMappings 拆分到不同的 list 当中去。
  5. 最后把 ResultMap 当中的所有属性都变成不可变的。

总结

从 ResultMapping 和 ResultMap 两个类内都有 Builder 之类,看到 mybatis 在构造多属性的对象时候大量使用了 builder 设计模式。

下篇继续分析 mapper.xml 当中的 sql 节点和数据库操作节点的解析源代码分析。

—EOF—