前一章节已经介绍了,把方法分解成什么样子来分析,这里先来分析一个方法resultMapElements,在这个方法前还有cacheRefElement与cacheElement,但是由于配置文件中没有配置这2项,所以这里就先跳过。而parameterMapElement在最新的MyBatis中是过时的,也先跳过,以后可以在补充。
1 配置文件
<resultMap id="BaseResultMap" type="cn.vansky.schedule.time.role.bo.Role"> <id column="Id" property="id" jdbcType="INTEGER" /> <result column="role_name" property="roleName" jdbcType="VARCHAR" /> <result column="role_remark" property="roleRemark" jdbcType="VARCHAR" /> <result column="is_delete" property="isDelete" jdbcType="TINYINT" /> <result column="operation_user_name" property="operationUserName" jdbcType="VARCHAR" /> <result column="operation_time" property="operationTime" jdbcType="TIMESTAMP" /> </resultMap>
这里是使用自己扩展MyBatis的自动生成代码,生成的resultMap配置。
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) throws Exception { return resultMapElement(resultMapNode, Collections.<ResultMapping> emptyList()); }
这里是获取当前文件中所有resultMap对应的XML,然后分别对每个resultMap进行处理。这里会去捕获一个专门的异常,目前还不清楚是起什么作用,先继续往下分析。
3 方法resultMapElement
// resultMapNode是对应的resuleMap的XML信息,这里首先获取配置中的id,如果没有就自动生成一个id String id = resultMapNode.getStringAttribute("id", resultMapNode.getValueBasedIdentifier()); // 那么这行很明显是获取type了,如果没有就获取ofType,还没有就获取resultType,还是没有就获取javaType String type = resultMapNode.getStringAttribute("type", resultMapNode.getStringAttribute("ofType", resultMapNode.getStringAttribute("resultType", resultMapNode.getStringAttribute("javaType")))); // 猜想是获取继承的父类 String extend = resultMapNode.getStringAttribute("extends"); // Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping"); // 获取type对应的Class Class<?> typeClass = resolveClass(type); Discriminator discriminator = null; List<ResultMapping> resultMappings = new ArrayList<ResultMapping>(); // 这里additionalResultMappings是空列表,而不是null resultMappings.addAll(additionalResultMappings); // 获取子节点id及result 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 { // id与result都走这里 ArrayList<ResultFlag> flags = new ArrayList<ResultFlag>(); if ("id".equals(resultChild.getName())) { flags.add(ResultFlag.ID); } resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags)); } }
4 buildResultMappingFromContext
以下都是以ID为例,进行分析。
private ResultMapping buildResultMappingFromContext(XNode context, Class<?> resultType, ArrayList<ResultFlag> flags) throws Exception { // id String property = context.getStringAttribute("property"); // Id String column = context.getStringAttribute("column"); // null String javaType = context.getStringAttribute("javaType"); // INTEGER String jdbcType = context.getStringAttribute("jdbcType"); // null String nestedSelect = context.getStringAttribute("select"); // null String nestedResultMap = context.getStringAttribute("resultMap", processNestedResultMappings(context, Collections.<ResultMapping> emptyList())); // null String notNullColumn = context.getStringAttribute("notNullColumn"); // null String columnPrefix = context.getStringAttribute("columnPrefix"); // null String typeHandler = context.getStringAttribute("typeHandler"); // null String resulSet = context.getStringAttribute("resultSet"); // null String foreignColumn = context.getStringAttribute("foreignColumn"); // false boolean lazy = "lazy".equals(context.getStringAttribute("fetchType", configuration.isLazyLoadingEnabled() ? "lazy" : "eager")); // null Class<?> javaTypeClass = resolveClass(javaType); @SuppressWarnings("unchecked") // null Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler); // 获取到JdbcType JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType); // 这里就会构建生成一个ResultMapping return builderAssistant.buildResultMapping(resultType, property, column, javaTypeClass, jdbcTypeEnum, nestedSelect, nestedResultMap, notNullColumn, columnPrefix, typeHandlerClass, flags, resulSet, foreignColumn, lazy); }
5 MapperBuilderAssistant的buildResultMapping方法
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) { // 这里如果配置中有javaType属性直接返回,否则通过type配置的类及属性获取对应的Class Class<?> javaTypeClass = resolveResultJavaType(resultType, property, javaType); // 获取类型处理器 TypeHandler<?> typeHandlerInstance = resolveTypeHandler(javaTypeClass, typeHandler); // List<ResultMapping> composites = parseCompositeColumnName(column); if (composites.size() > 0) column = null; // 初始化一些内部信息 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(); }
6 ResultMapping
6.1 属性
/** 全局配类 */ private Configuration configuration; /** id */ private String property; /** Id */ private String column; /** javaType */ private Class<?> javaType; /** JdbcType */ private JdbcType jdbcType; /** 类型处理器 */ private TypeHandler<?> typeHandler; private String nestedResultMapId; private String nestedQueryId; private Set<String> notNullColumns; private String columnPrefix; private List<ResultFlag> flags; private List<ResultMapping> composites; private String resultSet; private String foreignColumn; /** false */ private boolean lazy;
MyBatis的地址http://mybatis.github.io/mybatis-3/zh/sqlmap-xml.html#Result_Maps这里有很多例子,喜欢的童鞋可以多去研究一下。
当对id及result都遍历以后,会生成List<ResultMapping>。
ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping); try { return resultMapResolver.resolve(); } catch (IncompleteElementException e) { configuration.addIncompleteResultMap(resultMapResolver); throw e; }
如果这里解析失败会抛出前面出现的捕获异常,并把错误的解析放入Configuration(全局配置类)的Collection<ResultMapResolver> incompleteResultMaps = new LinkedList<ResultMapResolver>()。
7 MapperBuilderAssistant的addResultMap方法
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; }
这里没有具体介绍,还需要慢慢深究。下面来看最终的ResultMap信息。
8 ResultMap属性
private String id; private Class<?> type; private List<ResultMapping> resultMappings; private List<ResultMapping> idResultMappings; private List<ResultMapping> constructorResultMappings; private List<ResultMapping> propertyResultMappings; private Set<String> mappedColumns; private Discriminator discriminator; private boolean hasNestedResultMaps; private boolean hasNestedQueries; private Boolean autoMapping;
至此最终的ResultMap信息出来了。
总结:
这里很多东西,作者也是一点一点去研究,而且实际项目中的配置也不是特别的多,所以有些还待完善。
原文:http://my.oschina.net/u/1269959/blog/522346