MyBatis會把XML文件中的節點解析封裝成ResultMap,供結果映射使用
從XMLMapperBuilder類的resultMapElements方法看起
private void resultMapElements(List<XNode> list) throws Exception {
//基本上就是循環把resultMap加入到Configuration裏去,保持2份,一份縮略,一分全名
for (XNode resultMapNode : list) {
try {
//循環調resultMapElement
resultMapElement(resultMapNode);
} catch (IncompleteElementException e) {
// ignore, it will be retried
}
}
}
private ResultMap resultMapElement(XNode resultMapNode) throws Exception {
return resultMapElement(resultMapNode, Collections.<ResultMapping> emptyList());
}
private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings) throws Exception {
// <resultMap id="userResultMap" type="User">
// <id property="id" column="user_id" />
// <result property="username" column="username"/>
// <result property="password" column="password"/>
// </resultMap>
...
//如果不存在id屬性則自動生成
String id = resultMapNode.getStringAttribute("id",
resultMapNode.getValueBasedIdentifier());
//拿到返回類型
String type = resultMapNode.getStringAttribute("type",
resultMapNode.getStringAttribute("ofType",
resultMapNode.getStringAttribute("resultType",
resultMapNode.getStringAttribute("javaType"))));
//高級功能,支持繼承
// <resultMap id="carResult" type="Car" extends="vehicleResult">
// <result property="doorCount" column="door_count" />
// </resultMap>
String extend = resultMapNode.getStringAttribute("extends");
//autoMapping
Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");
//獲得返回類型的Class
Class<?> typeClass = resolveClass(type);
//鑑別器
Discriminator discriminator = null;
//解析結果封裝成ResultMapping,放進list裏
List<ResultMapping> resultMappings = new ArrayList<ResultMapping>();
resultMappings.addAll(additionalResultMappings);
List<XNode> resultChildren = resultMapNode.getChildren();
for (XNode resultChild : resultChildren) {
if ("constructor".equals(resultChild.getName())) {
//1.解析result map的constructor
processConstructorElement(resultChild, typeClass, resultMappings);
} else if ("discriminator".equals(resultChild.getName())) {
//2.解析result map的discriminator(鑑別器)
discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
} else {
//3.解析除上面兩種以外的節點
List<ResultFlag> flags = new ArrayList<ResultFlag>();
if ("id".equals(resultChild.getName())) {
flags.add(ResultFlag.ID);
}
//調buildResultMappingFromContext,得到ResultMapping
resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
}
}
//最後再調ResultMapResolver得到ResultMap
ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
try {
return resultMapResolver.resolve();
} catch (IncompleteElementException e) {
configuration.addIncompleteResultMap(resultMapResolver);
throw e;
}
}
上面解析分了三種情況:1.解析result map的constructor;2.解析result map的discriminator(鑑別器);3.解析除上面兩種以外的節點
1.解析result map的constructor
//<constructor>
// <idArg column="blog_id" javaType="int"/>
//</constructor>
private void processConstructorElement(XNode resultChild, Class<?> resultType, List<ResultMapping> resultMappings) throws Exception {
List<XNode> argChildren = resultChild.getChildren();
for (XNode argChild : argChildren) {
List<ResultFlag> flags = new ArrayList<ResultFlag>();
//結果標誌加上ID和CONSTRUCTOR
flags.add(ResultFlag.CONSTRUCTOR);
if ("idArg".equals(argChild.getName())) {
flags.add(ResultFlag.ID);//加上ID標誌
}
resultMappings.add(buildResultMappingFromContext(argChild, resultType, flags));
}
}
private ResultMapping buildResultMappingFromContext(XNode context, Class<?> resultType, List<ResultFlag> flags) throws Exception {
//<id property="id" column="author_id"/>
//<result property="username" column="author_username"/>
//下面拿到各種屬性
String property = context.getStringAttribute("property");
String column = context.getStringAttribute("column");
String javaType = context.getStringAttribute("javaType");
String jdbcType = context.getStringAttribute("jdbcType");
String nestedSelect = context.getStringAttribute("select");
//處理嵌套的result map
String nestedResultMap = context.getStringAttribute("resultMap",
processNestedResultMappings(context, Collections.<ResultMapping> emptyList()));
String notNullColumn = context.getStringAttribute("notNullColumn");
String columnPrefix = context.getStringAttribute("columnPrefix");
String typeHandler = context.getStringAttribute("typeHandler");
String resulSet = context.getStringAttribute("resultSet");
String foreignColumn = context.getStringAttribute("foreignColumn");
boolean lazy = "lazy".equals(context.getStringAttribute("fetchType", configuration.isLazyLoadingEnabled() ? "lazy" : "eager"));
Class<?> javaTypeClass = resolveClass(javaType);
@SuppressWarnings("unchecked")
Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
//去調builderAssistant.buildResultMapping
return builderAssistant.buildResultMapping(resultType, property, column, javaTypeClass, jdbcTypeEnum, nestedSelect, nestedResultMap, notNullColumn, columnPrefix, typeHandlerClass, flags, resulSet, foreignColumn, lazy);
}
public ResultMapping buildResultMapping(
Class<?> resultType,
String property,
String column,
Class<?> javaType,
JdbcType jdbcType,
String nestedSelect,
String nestedResultMap,
String notNullColumn,
String columnPrefix,
Class<? extends TypeHandler<?>> typeHandler,
List<ResultFlag> flags,
String resultSet,
String foreignColumn,
boolean lazy) {
Class<?> javaTypeClass = resolveResultJavaType(resultType, property, javaType);
TypeHandler<?> typeHandlerInstance = resolveTypeHandler(javaTypeClass, typeHandler);
//解析複合的列名,一般用不到,返回的是空
List<ResultMapping> composites = parseCompositeColumnName(column);
if (composites.size() > 0) {
column = null;
}
//構建result map
ResultMapping.Builder builder = new ResultMapping.Builder(configuration, property, column, javaTypeClass);
builder.jdbcType(jdbcType);
builder.nestedQueryId(applyCurrentNamespace(nestedSelect, true));
builder.nestedResultMapId(applyCurrentNamespace(nestedResultMap, true));
builder.resultSet(resultSet);
builder.typeHandler(typeHandlerInstance);
builder.flags(flags == null ? new ArrayList<ResultFlag>() : flags);
builder.composites(composites);
builder.notNullColumns(parseMultipleColumnNames(notNullColumn));
builder.columnPrefix(columnPrefix);
builder.foreignColumn(foreignColumn);
builder.lazy(lazy);
return builder.build();
}
最終是調用了助手類實例builderAssistant的buildResultMapping構建一個ResultMapping返回出去,然後加入ResultMapping的集合裏
2.解析result map的discriminator(鑑別器)
//<discriminator javaType="int" column="draft">
// <case value="1" resultMap="DraftPostMap"/>
//</discriminator>
private Discriminator processDiscriminatorElement(XNode context, Class<?> resultType, List<ResultMapping> resultMappings) throws Exception {
String column = context.getStringAttribute("column");
String javaType = context.getStringAttribute("javaType");
String jdbcType = context.getStringAttribute("jdbcType");
String typeHandler = context.getStringAttribute("typeHandler");
Class<?> javaTypeClass = resolveClass(javaType);
@SuppressWarnings("unchecked")
Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
Map<String, String> discriminatorMap = new HashMap<String, String>();
//解析子節點
for (XNode caseChild : context.getChildren()) {
String value = caseChild.getStringAttribute("value");
//拿到resultMap屬性,拿不到就進行遞歸resultMap解析
String resultMap = caseChild.getStringAttribute("resultMap", processNestedResultMappings(caseChild, resultMappings));
discriminatorMap.put(value, resultMap);//存進map
}
return builderAssistant.buildDiscriminator(resultType, column, javaTypeClass, jdbcTypeEnum, typeHandlerClass, discriminatorMap);
}
public Discriminator buildDiscriminator(
Class<?> resultType,
String column,
Class<?> javaType,
JdbcType jdbcType,
Class<? extends TypeHandler<?>> typeHandler,
Map<String, String> discriminatorMap) {
ResultMapping resultMapping = buildResultMapping(
resultType,
null,
column,
javaType,
jdbcType,
null,
null,
null,
null,
typeHandler,
new ArrayList<ResultFlag>(),
null,
null,
false);
Map<String, String> namespaceDiscriminatorMap = new HashMap<String, String>();
for (Map.Entry<String, String> e : discriminatorMap.entrySet()) {
String resultMap = e.getValue();
//加上命名空間前綴
resultMap = applyCurrentNamespace(resultMap, true);
namespaceDiscriminatorMap.put(e.getKey(), resultMap);
}
Discriminator.Builder discriminatorBuilder = new Discriminator.Builder(configuration, resultMapping, namespaceDiscriminatorMap);
return discriminatorBuilder.build();
}
上面可以看到,最終還是會創建一個resultMapping,而鑑別的映射結果則是存進map裏,最後傳給鑑別器構造器構建一個鑑別器返回
3.解析除上面兩種以外的節點
resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
這裏直接調用了buildResultMappingFromContext方法,上面解析第一種情況時已經列出。
當把resultMap下所有子節點解析封裝成ResultMapping,並裝進集合後,就進行最後一步:構建ResultMap對象
//最後再調ResultMapResolver得到ResultMap
ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
try {
return resultMapResolver.resolve();
} catch (IncompleteElementException e) {
configuration.addIncompleteResultMap(resultMapResolver);
throw e;
}
public ResultMap resolve() {
//解析又去調用MapperBuilderAssistant.addResultMap
return assistant.addResultMap(this.id, this.type, this.extend, this.discriminator, this.resultMappings, this.autoMapping);
}
//增加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.Builder resultMapBuilder = new ResultMap.Builder(configuration, id, type, resultMappings, autoMapping);
if (extend != null) {
if (!configuration.hasResultMap(extend)) {
//這裏還沒解析引用到的其他ResultMap,拋異常退出,最後再構建
throw new IncompleteElementException("Could not find a parent resultmap with id '" + extend + "'");
}
ResultMap resultMap = configuration.getResultMap(extend);
//拿到繼承ResultMappings
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)) {
//把父ResultMapping的構造方法節點去掉
extendedResultMappingsIter.remove();
}
}
}
resultMappings.addAll(extendedResultMappings);
}
resultMapBuilder.discriminator(discriminator);
ResultMap resultMap = resultMapBuilder.build();
//存到configuration中
configuration.addResultMap(resultMap);
return resultMap;
}
最終解析Result配置信息封裝成ResultMap對象,並存進configuration中。