Mybatis加载解析Mapper(xml)文件第二讲
程序员文章站
2022-05-09 22:35:51
...
SqlSessionFactory初始化:http://donald-draper.iteye.com/admin/blogs/2331917
Mybatis加载解析Mapper(xml)文件第一讲:http://donald-draper.iteye.com/blog/2333125
解析Mapper对应的xml文件,实际上是解析xml的mapper Xnode,具体到namespace属性,及cache,cache-ref,parameterMap,resultMap,sql,及select|insert|update|delete子节点,在上一篇中,我们讲到namespace属性,及cache,cache-ref,parameterMap,这三部分的解析,在这一篇来讲一下,resultMap,sql,及select|insert|update|delete子节点的解析
首先从下面这个方法来看
//加载Mapper xml文件,并解析
//XMLMapperBuilder
//Configuration,添加Mapper xml文件名到Set<String> loadedResources;
//其中key为class完整名,com.mapper.UserMapper
//配置resultMap
resultMapElements(context.evalNodes("/mapper/resultMap"));
//XMLMapperBuilder
//遍历解析resultMap节点
//ResultMapping
//ResultFlag
//ResultMapResolver,ResultMap处理器
//MapperBuilderAssistant
//构造ResultMap,并将ResultMap映射关系添加到configuration
//将resultMap映射关系添加到configuration
resultMaps = new StrictMap("Result Maps collection");
HashMap<nameSpace,ResultMap>,key为ResultMap的全局命名空间id
//ResultMap
从以上分析可以看出resultMap节点的解析,首先获取resultMap的id,type等属性,再处理其子节点result,constructor,discriminator;对于result节点,解析column,property,jdbcType等属性,包装成ResultMapping,添加resultMappings集合中ArrayList<ResultMapping>;最后根据resultMap的id,type等属性和
resultMappings构建ResultMap,如果extend的父ResultMap不存在,则抛出IncompleteElementException,并添加到configuration的,IncompleteResultMap-LinkedList<ResultMapResolver>中,如果存在则,添加的configuration的resultMaps中。
//配置sql
sqlElement(context.evalNodes("/mapper/sql"));
//解析所有sql节点
从上可以看出解析Sql节点是将Sql节点对应Xnode与id映射关系,添加到sqlFragments-HashMap<id,XNode>中;
//配置select|insert|update|delete statement
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
//处理select|insert|update|delete节点信息
//XMLStatementBuilder
//解析SelectKey节点信息
//解析SelectKey节点信息,具体实现
//configuration
//添加keyGenerators与其命名空间的映射关系到keyGenerators中
//keyGenerators:Map<nameSpace ,KeyGenerator>
回到这一句
//根据select|insert|update|delete节点的属性信息,构建MappedStatement
//并添加到configuration的mappedStatements的Map中Map<id-nameSpace,MappedStatement>
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, langDriver);
//MapperBuilderAssistant
//MappedStatement
//BoundSql,sql的包装类
从上面可以看出,解析select|insert|update|delete-Xnode信息,首先将节点信息包装成XMLStatementBuilder,由XMLStatementBuilder,去解析,当XMLStatementBuilder解析时,statement节点Xnode的参考的缓存不存在,则抛出IncompleteElementException,则将XMLStatementBuilder添加到configuration的IncompleteStatement集合中,
LinkedList<XMLStatementBuilder>;如果缓存引用已解决,则解析SelectKey节点信息,
跟SelectKey节点的属性信息,构建keyStatement,并添加configuration的mappedStatements的Map中,Map<id-nameSpace,MappedStatement>,根据keyStatement,构建SelectKeyGenerator,并添加在configuration的keyGenerators-Map中,如果无SelectKey节点,则根据statement节点的useGeneratedKeys属性和全局配置信息isUseGeneratedKeys与SqlCommandType.INSERT产生对应的KeyGenerator;根据statement节点和KeyGenerator,构造MapperStatement,添加到configuration的mappedStatements的Map中。
//绑定Mapper的命名空间
bindMapperForNamespace();
//configuration,将资源信息,添加的loadedResources中Set<resource:nameSpace>
//mapperRegistry,注册mapInterface
//MapperRegistry
//MapperRegistry
//MapperProxy
//MapperMethod
从上可以看出Configuration添加MapperInterface,就是MapperRegistry注册到其
HashMap<Class,MapperProxyFactory>中,MapperProxyFactory是MapperInterface的代理,
生成MapperInterface的MapperProxy代理实例,MapperProxy中利用Map<Method,MapperMethod>,
实现二级缓存;MapperInterface执行DML实际上是,通过MapperProxy反射,调用MapperMethod的方法。
//Resources
//从configuration中移除未处理完成的ResultMaps
parsePendingResultMaps();
//从configuration中移除未完成的CacheRefs
parsePendingChacheRefs();
//从configuration中移除未完成的Statements
parsePendingStatements();
总结:
解析Mapper对应的xml文件,实际上是解析xml的mapper Xnode,具体到namespace属性,及cache,cache-ref,parameterMap,resultMap,sql,及select|insert|update|delete子节点,当解析完mapper Xnode时,将Mapper的资源id,
添加configuration的Set<class.name> resource;然后绑定Mapper的命名空间,实际做的是:通过Configuration的MapperRegistry,注册到MapperRegistry的HashMap<Class,MapperProxyFactory>中,MapperProxyFactory是MapperInterface的代理,
生成MapperInterface的MapperProxy代理实例,MapperProxy中利用Map<Method,MapperMethod>,实现二级缓存,MapperInterface执行DML实际上是,通过MapperProxy反射,调用MapperMethod的方法;然后处理未完成的ResultMap,
CacheRefs,Statements解析处理任务,完成后,从configuration中未完成IncompleteResultMaps、CacheRefs、StatementsParser中移除任务。
各小节总结:
cache-ref:
从分析配置cache-ref,实际上,将cache和cache-ref的命名空间的映射关系添加到configuration中,并从configuration的获取cacheRefNamespace对应的Cache,如果cache-ref的cacheRefNamespace对应的缓存,不存在,则抛出IncompleteElementException,并将对应的CacheRefResolver添加到configuration的IncompleteCacheRef集合中Linklist<CacheRefResolver>;
cache:
从上的分析可以看出Cache的节点的解析,实际上是,获取cache节点的type对应的Class,
cache节点的eviction对应的缓存算法Class,以及刷新间隔,读写属性,构造CacheBuilder
,并添加的configuration的二级缓存StrictMap<nameSpace,CacheBuilder>;
parameterMap:
从上的分析可以看出ParameterMap的解析实际是解析ParameterMap的id,type属性和
parameter子节点;然后解析parameter的property,javaType,jdbcType,typeHalder,resultMap的属性,根据这些属性构建parameterMapping,并添加的parameterMappings(ArrayList<ParameterMapping>)集合中;
然后再根据id,type属性和parameterMappings,构造ParameterMap,并添加到configuration的parameterMaps中;
resultMap:
从以上分析可以看出resultMap节点的解析,首先获取resultMap的id,type等属性,再处理其子节点result,constructor,discriminator;对于result节点,解析column,property,jdbcType等属性,包装成ResultMapping,添加resultMappings集合中ArrayList<ResultMapping>;最后根据resultMap的id,type等属性和
resultMappings构建ResultMap,如果extend的父ResultMap不存在,则抛出IncompleteElementException,并添加到configuration
的,IncompleteResultMap-LinkedList<ResultMapResolver>中,如果存在则,添加的configuration的resultMaps中;
Sql:
从上可以看出解析Sql节点是将Sql节点对应Xnode与id映射关系,添加到sqlFragments-HashMap<id,XNode>中;
select|insert|update|delete:
从上面可以看出,解析select|insert|update|delete-Xnode信息,首先将节点信息包装成XMLStatementBuilder,由XMLStatementBuilder,去解析,当XMLStatementBuilder解析时,statement节点Xnode的参考的缓存不存在,则抛出IncompleteElementException,则将XMLStatementBuilder添加到configuration的IncompleteStatement集合中,
LinkedList<XMLStatementBuilder>;如果缓存引用已解决,则解析SelectKey节点信息,
跟SelectKey节点的属性信息,构建keyStatement,并添加configuration的mappedStatements的Map中,Map<id-nameSpace,MappedStatement>,根据keyStatement,构建SelectKeyGenerator,并添加在configuration的keyGenerators-Map中,如果无SelectKey节点,则根据statement节点的useGeneratedKeys属性和全局配置信息isUseGeneratedKeys与SqlCommandType.INSERT产生对应的KeyGenerator;根据statement节点和KeyGenerator,构造MapperStatement,添加到configuration的mappedStatements的Map中。
//SqlCommandType
//StatementTypes
Mybatis加载解析Mapper(xml)文件第一讲:http://donald-draper.iteye.com/blog/2333125
解析Mapper对应的xml文件,实际上是解析xml的mapper Xnode,具体到namespace属性,及cache,cache-ref,parameterMap,resultMap,sql,及select|insert|update|delete子节点,在上一篇中,我们讲到namespace属性,及cache,cache-ref,parameterMap,这三部分的解析,在这一篇来讲一下,resultMap,sql,及select|insert|update|delete子节点的解析
首先从下面这个方法来看
//加载Mapper xml文件,并解析
private void mapperElement(XNode parent) throws Exception { if(parent != null) { for(Iterator i$ = parent.getChildren().iterator(); i$.hasNext();) { XNode child = (XNode)i$.next(); if("package".equals(child.getName())) { String mapperPackage = child.getStringAttribute("name"); configuration.addMappers(mapperPackage); } else { String resource = child.getStringAttribute("resource"); String url = child.getStringAttribute("url"); String mapperClass = child.getStringAttribute("class"); //根据配置的resource,解析Mapper if(resource != null && url == null && mapperClass == null) { ErrorContext.instance().resource(resource); //加载Mapper的resource文件 InputStream inputStream = Resources.getResourceAsStream(resource); 构建XMLMapperBuilder XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments()); mapperParser.parse(); } else if(resource == null && url != null && mapperClass == null) { ErrorContext.instance().resource(url); InputStream inputStream = Resources.getUrlAsStream(url); XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments()); mapperParser.parse(); } else //这一部分放到下一篇讲 //根据配置的class,解析Mapper if(resource == null && url == null && mapperClass != null) { Class mapperInterface = Resources.classForName(mapperClass); //mapperInterface信息添加到configuration configuration.addMapper(mapperInterface); } else { throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one."); } } } } }
//XMLMapperBuilder
public class XMLMapperBuilder extends BaseBuilder { private XPathParser parser; private MapperBuilderAssistant builderAssistant; private Map sqlFragments; private String resource; //构造XMLMapperBuilder public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map sqlFragments) { this(new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver()), configuration, resource, sqlFragments); } private XMLMapperBuilder(XPathParser parser, Configuration configuration, String resource, Map sqlFragments) { super(configuration); //构建MapperBuilderAssistant builderAssistant = new MapperBuilderAssistant(configuration, resource); this.parser = parser; this.sqlFragments = sqlFragments; this.resource = resource; } public void parse() { if(!configuration.isResourceLoaded(resource)) { //如果configuration没有加载文件,则解析Mapper xml文件, <mapper namespace="test.Dao.UserMapper"> configurationElement(parser.evalNode("/mapper")); //将资源添加到configuration的Set<class.name> resource configuration.addLoadedResource(resource); //绑定Mapper的命名空间 bindMapperForNamespace(); } //从configuration中移除未完成的ResultMaps parsePendingResultMaps(); //从configuration中移除未完成的ChacheRefs parsePendingChacheRefs(); //从configuration中移除未完成的Statements parsePendingStatements(); } //根据mapper Xnode 配置,namespace,cache,cache-ref,parameterMap,resultMap, //sql,及select|insert|update|delete子节点 private void configurationElement(XNode context) { try { String namespace = context.getStringAttribute("namespace"); builderAssistant.setCurrentNamespace(namespace); cacheRefElement(context.evalNode("cache-ref")); cacheElement(context.evalNode("cache")); parameterMapElement(context.evalNodes("/mapper/parameterMap")); //上面这一部分我们已经在一片讲过,今天来讲下面这一部分 resultMapElements(context.evalNodes("/mapper/resultMap")); sqlElement(context.evalNodes("/mapper/sql")); buildStatementFromContext(context.evalNodes("select|insert|update|delete")); } catch(Exception e) { throw new RuntimeException((new StringBuilder()).append("Error parsing Mapper XML. Cause: ").append(e).toString(), e); } } }
//Configuration,添加Mapper xml文件名到Set<String> loadedResources;
//其中key为class完整名,com.mapper.UserMapper
public void addLoadedResource(String resource) { loadedResources.add(resource); }
//配置resultMap
resultMapElements(context.evalNodes("/mapper/resultMap"));
<!-- <resultMap id="BaseResultMap" type="test.entity.User"> <id column="id" property="id" jdbcType="INTEGER" /> <result column="name" property="name" jdbcType="VARCHAR" /> <result column="age" property="age" jdbcType="INTEGER" /> <result column="registerTime" property="registertime" jdbcType="TIMESTAMP" /> </resultMap> -->
//XMLMapperBuilder
//遍历解析resultMap节点
private void resultMapElements(List list) throws Exception { for(Iterator i$ = list.iterator(); i$.hasNext();) { XNode resultMapNode = (XNode)i$.next(); try { //解析resultMap节点 resultMapElement(resultMapNode); } catch(IncompleteElementException e) { } } } //解析resultMap节点 private ResultMap resultMapElement(XNode resultMapNode) throws Exception { //委托给resultMapElement方法 return resultMapElement(resultMapNode, Collections.emptyList()); } //具体解析resultMap节点 private ResultMap resultMapElement(XNode resultMapNode, List additionalResultMappings) throws Exception { ResultMapResolver resultMapResolver; ErrorContext.instance().activity((new StringBuilder()).append("processing ").append(resultMapNode.getValueBasedIdentifier()).toString()); //获取resultMap的id,type,extends,autoMapping String id = resultMapNode.getStringAttribute("id", resultMapNode.getValueBasedIdentifier()); String type = resultMapNode.getStringAttribute("type", resultMapNode.getStringAttribute("ofType", resultMapNode.getStringAttribute("resultType", resultMapNode.getStringAttribute("javaType")))); String extend = resultMapNode.getStringAttribute("extends"); Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping", null); Class typeClass = resolveClass(type); Discriminator discriminator = null; List resultMappings = new ArrayList(); resultMappings.addAll(additionalResultMappings); List resultChildren = resultMapNode.getChildren(); //resultMap节点的所有result子节点,根据result节点信息,构造ResultMapping //并添加到resultMappings,ArrayList<ResultMapping> for(Iterator i$ = resultChildren.iterator(); i$.hasNext();) { XNode resultChild = (XNode)i$.next(); if("constructor".equals(resultChild.getName())) //constructor子节点处理 processConstructorElement(resultChild, typeClass, resultMappings); else if("discriminator".equals(resultChild.getName())) { //discriminator子节点处理 discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings); } else { //result子节点的处理,如果为id子节点,则ResultFlag.ID添加到flags集合中 ArrayList flags = new ArrayList(); if("id".equals(resultChild.getName())) flags.add(ResultFlag.ID); resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags)); } } //构造resultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping); return resultMapResolver.resolve(); IncompleteElementException e; e; //如果有IncompleteElementException,则将resultMapResolver添加的IncompleteResultMap结合中 //LinkedList<ResultMapResolver> configuration.addIncompleteResultMap(resultMapResolver); throw e; } //处理constructor子节点 private void processConstructorElement(XNode resultChild, Class resultType, List resultMappings) throws Exception { List argChildren = resultChild.getChildren(); XNode argChild; ArrayList flags; for(Iterator i$ = argChildren.iterator(); i$.hasNext(); resultMappings.add(buildResultMappingFromContext(argChild, resultType, flags))) { argChild = (XNode)i$.next(); flags = new ArrayList(); flags.add(ResultFlag.CONSTRUCTOR); if("idArg".equals(argChild.getName())) flags.add(ResultFlag.ID); } } //处理discriminator子节点 private Discriminator processDiscriminatorElement(XNode context, Class resultType, List 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); Class typeHandlerClass = resolveClass(typeHandler); JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType); Map discriminatorMap = new HashMap(); String value; String resultMap; for(Iterator i$ = context.getChildren().iterator(); i$.hasNext(); discriminatorMap.put(value, resultMap)) { XNode caseChild = (XNode)i$.next(); value = caseChild.getStringAttribute("value"); resultMap = caseChild.getStringAttribute("resultMap", processNestedResultMappings(caseChild, resultMappings)); } return builderAssistant.buildDiscriminator(resultType, column, javaTypeClass, jdbcTypeEnum, typeHandlerClass, discriminatorMap); } //result和id构造ResultMapping方法 private ResultMapping buildResultMappingFromContext(XNode context, Class resultType, ArrayList flags) throws Exception { 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"); String nestedResultMap = context.getStringAttribute("resultMap", processNestedResultMappings(context, Collections.emptyList())); String notNullColumn = context.getStringAttribute("notNullColumn"); String columnPrefix = context.getStringAttribute("columnPrefix"); String typeHandler = context.getStringAttribute("typeHandler"); Class javaTypeClass = resolveClass(javaType); Class typeHandlerClass = resolveClass(typeHandler); JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType); return builderAssistant.buildResultMapping(resultType, property, column, javaTypeClass, jdbcTypeEnum, nestedSelect, nestedResultMap, notNullColumn, columnPrefix, typeHandlerClass, flags); } //构建resultMapping public ResultMapping buildResultMapping(Class resultType, String property, String column, Class javaType, JdbcType jdbcType, String nestedSelect, String nestedResultMap, String notNullColumn, String columnPrefix, Class typeHandler, List flags) { ResultMapping resultMapping = assembleResultMapping(resultType, property, column, javaType, jdbcType, nestedSelect, nestedResultMap, notNullColumn, columnPrefix, typeHandler, flags); return resultMapping; } //组装ResultMapping private ResultMapping assembleResultMapping(Class resultType, String property, String column, Class javaType, JdbcType jdbcType, String nestedSelect, String nestedResultMap, String notNullColumn, String columnPrefix, Class typeHandler, List flags) { Class javaTypeClass = resolveResultJavaType(resultType, property, javaType); TypeHandler typeHandlerInstance = resolveTypeHandler(javaTypeClass, typeHandler); List composites = parseCompositeColumnName(column); if(composites.size() > 0) column = null; org.apache.ibatis.mapping.ResultMapping.Builder builder = new org.apache.ibatis.mapping.ResultMapping.Builder(configuration, property, column, javaTypeClass); builder.jdbcType(jdbcType); builder.nestedQueryId(applyCurrentNamespace(nestedSelect, true)); builder.nestedResultMapId(applyCurrentNamespace(nestedResultMap, true)); builder.typeHandler(typeHandlerInstance); builder.flags(((List) (flags != null ? flags : ((List) (new ArrayList()))))); builder.composites(composites); builder.notNullColumns(parseMultipleColumnNames(notNullColumn)); builder.columnPrefix(columnPrefix); return builder.build(); }
//ResultMapping
public class ResultMapping { public static class Builder { public Builder javaType(Class javaType) { resultMapping.javaType = javaType; return this; } //返回构建好的resultMapping public ResultMapping build() { validate(); //将flag,修改成unmodifiableList resultMapping.flags = Collections.unmodifiableList(resultMapping.flags); resultMapping.composites = Collections.unmodifiableList(resultMapping.composites); resolveTypeHandler(); return resultMapping; } private void resolveTypeHandler() { if(resultMapping.typeHandler == null && resultMapping.javaType != null) { //从configuration获取typeHandlerRegistry Configuration configuration = resultMapping.configuration; TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); //从typeHandlerRegistry获取typeHandler resultMapping.typeHandler = typeHandlerRegistry.getTypeHandler(resultMapping.javaType, resultMapping.jdbcType); } } //构造builder public Builder(Configuration configuration, String property, String column, Class javaType) { resultMapping = new ResultMapping(); resultMapping.configuration = configuration; resultMapping.property = property; resultMapping.column = column; resultMapping.javaType = javaType; resultMapping.flags = new ArrayList(); resultMapping.composites = new ArrayList(); } }
//ResultFlag
public final class ResultFlag extends Enum { public static ResultFlag[] values() { return (ResultFlag[])$VALUES.clone(); } public static ResultFlag valueOf(String name) { return (ResultFlag)Enum.valueOf(org/apache/ibatis/mapping/ResultFlag, name); } private ResultFlag(String s, int i) { super(s, i); } public static final ResultFlag ID; public static final ResultFlag CONSTRUCTOR; private static final ResultFlag $VALUES[]; static { ID = new ResultFlag("ID", 0); CONSTRUCTOR = new ResultFlag("CONSTRUCTOR", 1); $VALUES = (new ResultFlag[] { ID, CONSTRUCTOR }); } }
//ResultMapResolver,ResultMap处理器
public class ResultMapResolver { private final MapperBuilderAssistant assistant; private String id;//id属性 private Class type;// type属性 private String extend; private Discriminator discriminator; private List resultMappings; private Boolean autoMapping; public ResultMapResolver(MapperBuilderAssistant assistant, String id, Class type, String extend, Discriminator discriminator, List resultMappings, Boolean autoMapping) { this.assistant = assistant; this.id = id; this.type = type; this.extend = extend; this.discriminator = discriminator; this.resultMappings = resultMappings; this.autoMapping = autoMapping; } public ResultMap resolve() { return assistant.addResultMap(id, type, extend, discriminator, resultMappings, autoMapping); } }
//MapperBuilderAssistant
//构造ResultMap,并将ResultMap映射关系添加到configuration
public ResultMap addResultMap(String id, Class type, String extend, Discriminator discriminator, List resultMappings, Boolean autoMapping) { //获取ResultMap的全局命名空间 id = applyCurrentNamespace(id, false); extend = applyCurrentNamespace(extend, true); //构建ResultMap org.apache.ibatis.mapping.ResultMap.Builder resultMapBuilder = new org.apache.ibatis.mapping.ResultMap.Builder(configuration, id, type, resultMappings, autoMapping); ResultMap resultMap; if(extend != null) { //如果继承属性为true,则从configuration寻找父类的ResultMap,如果没有则抛出IncompleteElementException if(!configuration.hasResultMap(extend)) throw new IncompleteElementException((new StringBuilder()).append("Could not find a parent resultmap with id '").append(extend).append("'").toString()); resultMap = configuration.getResultMap(extend); List extendedResultMappings = new ArrayList(resultMap.getResultMappings()); extendedResultMappings.removeAll(resultMappings); boolean declaresConstructor = false; Iterator i$ = resultMappings.iterator(); do { if(!i$.hasNext()) break; ResultMapping resultMapping = (ResultMapping)i$.next(); if(!resultMapping.getFlags().contains(ResultFlag.CONSTRUCTOR)) continue; declaresConstructor = true; break; } while(true); if(declaresConstructor) { Iterator extendedResultMappingsIter = extendedResultMappings.iterator(); do { if(!extendedResultMappingsIter.hasNext()) break; if(((ResultMapping)extendedResultMappingsIter.next()).getFlags().contains(ResultFlag.CONSTRUCTOR)) extendedResultMappingsIter.remove(); } while(true); } resultMappings.addAll(extendedResultMappings); } resultMapBuilder.discriminator(discriminator); //获取构建的resultMap resultMap = resultMapBuilder.build(); //将resultMap映射关系添加到configuration configuration.addResultMap(resultMap); return resultMap; }
//将resultMap映射关系添加到configuration
resultMaps = new StrictMap("Result Maps collection");
HashMap<nameSpace,ResultMap>,key为ResultMap的全局命名空间id
public void addResultMap(ResultMap rm) { resultMaps.put(rm.getId(), rm); checkLocallyForDiscriminatedNestedResultMaps(rm); checkGloballyForDiscriminatedNestedResultMaps(rm); }
//ResultMap
public class ResultMap { private String id; private Class type; private List resultMappings; private List idResultMappings; private List constructorResultMappings; private List propertyResultMappings; private Set mappedColumns; private Discriminator discriminator; private boolean hasNestedResultMaps; private boolean hasNestedQueries; private Boolean autoMapping; public static class Builder { public ResultMap build() { if(resultMap.id == null) throw new IllegalArgumentException("ResultMaps must have an id"); resultMap.mappedColumns = new HashSet(); resultMap.idResultMappings = new ArrayList(); resultMap.constructorResultMappings = new ArrayList(); resultMap.propertyResultMappings = new ArrayList(); Iterator i$ = resultMap.resultMappings.iterator(); do { if(!i$.hasNext()) break; ResultMapping resultMapping = (ResultMapping)i$.next(); resultMap.hasNestedQueries = resultMap.hasNestedQueries || resultMapping.getNestedQueryId() != null; resultMap.hasNestedResultMaps = resultMap.hasNestedResultMaps || resultMapping.getNestedResultMapId() != null; String column = resultMapping.getColumn(); if(column != null) resultMap.mappedColumns.add(column.toUpperCase(Locale.ENGLISH)); else if(resultMapping.isCompositeResult()) { Iterator i$ = resultMapping.getComposites().iterator(); do { if(!i$.hasNext()) break; ResultMapping compositeResultMapping = (ResultMapping)i$.next(); String compositeColumn = compositeResultMapping.getColumn(); if(compositeColumn != null) resultMap.mappedColumns.add(compositeColumn.toUpperCase(Locale.ENGLISH)); } while(true); } 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); } while(true); if(resultMap.idResultMappings.isEmpty()) resultMap.idResultMappings.addAll(resultMap.resultMappings); 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节点的解析,首先获取resultMap的id,type等属性,再处理其子节点result,constructor,discriminator;对于result节点,解析column,property,jdbcType等属性,包装成ResultMapping,添加resultMappings集合中ArrayList<ResultMapping>;最后根据resultMap的id,type等属性和
resultMappings构建ResultMap,如果extend的父ResultMap不存在,则抛出IncompleteElementException,并添加到configuration的,IncompleteResultMap-LinkedList<ResultMapResolver>中,如果存在则,添加的configuration的resultMaps中。
//配置sql
sqlElement(context.evalNodes("/mapper/sql"));
//解析所有sql节点
private void sqlElement(List list) throws Exception { if(configuration.getDatabaseId() != null) //如果有数据源,则配置数据源信息 sqlElement(list, configuration.getDatabaseId()); //委托给sqlElement sqlElement(list, null); } //具体sql节点的处理 private void sqlElement(List list, String requiredDatabaseId) throws Exception { Iterator i$ = list.iterator(); do { if(!i$.hasNext()) break; XNode context = (XNode)i$.next(); //获取sql节点databaseId,id,属性 String databaseId = context.getStringAttribute("databaseId"); String id = context.getStringAttribute("id"); id = builderAssistant.applyCurrentNamespace(id, false); if(databaseIdMatchesCurrent(id, databaseId, requiredDatabaseId)) //将sql节点信息放入sqlFragments-Map<id,XNode>中,待解析select|insert|update|delete节点用 sqlFragments.put(id, context); } while(true); } //判断sql的数据源与requiredDatabaseId是否匹配 private boolean databaseIdMatchesCurrent(String id, String databaseId, String requiredDatabaseId) { if(requiredDatabaseId != null) { if(!requiredDatabaseId.equals(databaseId)) return false; } else { if(databaseId != null) return false; //如果databaseId与requiredDatabaseId相等,且不为null,则 //查看configuration的sqlFragments集合中是否存在id对应sqlFragment信息 if(sqlFragments.containsKey(id)) { XNode context = (XNode)sqlFragments.get(id); //若sql节点不含有databaseId属性则,返回false if(context.getStringAttribute("databaseId") != null) return false; } } return true; }
从上可以看出解析Sql节点是将Sql节点对应Xnode与id映射关系,添加到sqlFragments-HashMap<id,XNode>中;
//配置select|insert|update|delete statement
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
//处理select|insert|update|delete节点信息
private void buildStatementFromContext(List list) { if(configuration.getDatabaseId() != null) buildStatementFromContext(list, configuration.getDatabaseId()); //委托给buildStatementFromContext buildStatementFromContext(list, null); } //具体处理select|insert|update|delete节点信息 private void buildStatementFromContext(List list, String requiredDatabaseId) { for(Iterator i$ = list.iterator(); i$.hasNext();) { XNode context = (XNode)i$.next(); //根据Xnode节点信息构造XMLStatementBuilder XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId); try { //解析select|insert|update|delete-Xnode信息,并构建MapStatement,添加configuration的 //mappedStatements的Map中,Map<id-nameSpace,MappedStatement> statementParser.parseStatementNode(); } catch(IncompleteElementException e) { //如果缓存引用不存在,则将statementParser添加到 //configuration的IncompleteStatement集合中,LinkedList<XMLStatementBuilder> configuration.addIncompleteStatement(statementParser); } } }
//XMLStatementBuilder
public class XMLStatementBuilder extends BaseBuilder { public XMLStatementBuilder(Configuration configuration, MapperBuilderAssistant builderAssistant, XNode context) { this(configuration, builderAssistant, context, null); } public XMLStatementBuilder(Configuration configuration, MapperBuilderAssistant builderAssistant, XNode context, String databaseId) { super(configuration); this.builderAssistant = builderAssistant; this.context = context; requiredDatabaseId = databaseId; } //解析Statement XNode节点 public void parseStatementNode() { //获取Statement XNode的id,databaseId,fetchSize,timeout,fetchSize, //timeout,parameterMap,parameterType,resultMap,resultType,statementType //sqlCommandType,flushCache,useCache,resultOrdered,selectKey,keyProperty,keyColumn String id = context.getStringAttribute("id"); String databaseId = context.getStringAttribute("databaseId"); //如果databaseId与全局配置文件的requiredDatabaseId不同,则直接返回 if(!databaseIdMatchesCurrent(id, databaseId, requiredDatabaseId)) return; Integer fetchSize = context.getIntAttribute("fetchSize", null); Integer timeout = context.getIntAttribute("timeout", null); String parameterMap = context.getStringAttribute("parameterMap"); String parameterType = context.getStringAttribute("parameterType"); Class parameterTypeClass = resolveClass(parameterType); String resultMap = context.getStringAttribute("resultMap"); String resultType = context.getStringAttribute("resultType"); String lang = context.getStringAttribute("lang"); LanguageDriver langDriver = getLanguageDriver(lang); //获取resultType,类型Class Class resultTypeClass = resolveClass(resultType); String resultSetType = context.getStringAttribute("resultSetType"); //获取statementType属性,无则为StatementType.PREPARED.toString() StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString())); ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType); String nodeName = context.getNode().getNodeName(); //获取sqlCommandType属性 SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH)); boolean isSelect = sqlCommandType == SqlCommandType.SELECT; boolean flushCache = context.getBooleanAttribute("flushCache", Boolean.valueOf(!isSelect)).booleanValue(); boolean useCache = context.getBooleanAttribute("useCache", Boolean.valueOf(isSelect)).booleanValue(); boolean resultOrdered = context.getBooleanAttribute("resultOrdered", Boolean.valueOf(false)).booleanValue(); XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant); includeParser.applyIncludes(context.getNode()); //获取selectKey节点信息 List selectKeyNodes = context.evalNodes("selectKey"); if(configuration.getDatabaseId() != null) parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, configuration.getDatabaseId()); //解析SelectKeys节点 parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, null); SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass); String keyProperty = context.getStringAttribute("keyProperty"); String keyColumn = context.getStringAttribute("keyColumn"); String keyStatementId = (new StringBuilder()).append(id).append("!selectKey").toString(); //构建selectKey,全局唯一的命名空间id keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true); KeyGenerator keyGenerator; //如果配置中有keyStatementId对应的KeyGenerator,则返回KeyGenerator if(configuration.hasKeyGenerator(keyStatementId)) keyGenerator = configuration.getKeyGenerator(keyStatementId); else //否则产生KeyGenerator, //如果useGeneratedKeys属性存在,且为为true,则KeyGenerator为Jdbc3KeyGenerator //如果为useGeneratedKeys属性不存在,判断全局配置信息isUseGeneratedKeys和SqlCommandType.INSERT //的信息,如果为真,则KeyGenerator为NoKeyGenerator //KeyGenerator的具体含义,我们在后面的文章中,字面看是主键生成器 keyGenerator = ((KeyGenerator) (context.getBooleanAttribute("useGeneratedKeys", Boolean.valueOf(configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))).booleanValue() ? ((KeyGenerator) (new Jdbc3KeyGenerator())) : ((KeyGenerator) (new NoKeyGenerator())))); //根据select|insert|update|delete节点的属性信息,构建MappedStatement //并添加到configuration的mappedStatements的Map中,Map<id-nameSpace,MappedStatement> builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, langDriver); }
//解析SelectKey节点信息
public void parseSelectKeyNodes(String parentId, List list, Class parameterTypeClass, LanguageDriver langDriver, String skRequiredDatabaseId) { Iterator i$ = list.iterator(); do { if(!i$.hasNext()) break; XNode nodeToHandle = (XNode)i$.next(); String id = (new StringBuilder()).append(parentId).append("!selectKey").toString(); String databaseId = nodeToHandle.getStringAttribute("databaseId"); if(databaseIdMatchesCurrent(id, databaseId, skRequiredDatabaseId)) parseSelectKeyNode(id, nodeToHandle, parameterTypeClass, langDriver, databaseId); } while(true); }
//解析SelectKey节点信息,具体实现
public void parseSelectKeyNode(String id, XNode nodeToHandle, Class parameterTypeClass, LanguageDriver langDriver, String databaseId) { //获取SelectKey节点的resultType,keyProperty,statementType,useCache,keyGenerator //fetchSize,timeout,flushCache,parameterMap,resultMap等属性信息 String resultType = nodeToHandle.getStringAttribute("resultType"); Class resultTypeClass = resolveClass(resultType); StatementType statementType = StatementType.valueOf(nodeToHandle.getStringAttribute("statementType", StatementType.PREPARED.toString())); String keyProperty = nodeToHandle.getStringAttribute("keyProperty"); boolean executeBefore = "BEFORE".equals(nodeToHandle.getStringAttribute("order", "AFTER")); boolean useCache = false; boolean resultOrdered = false; KeyGenerator keyGenerator = new NoKeyGenerator(); Integer fetchSize = null; Integer timeout = null; boolean flushCache = false; String parameterMap = null; String resultMap = null; ResultSetType resultSetTypeEnum = null; SqlSource sqlSource = langDriver.createSqlSource(configuration, nodeToHandle, parameterTypeClass); SqlCommandType sqlCommandType = SqlCommandType.SELECT; //跟SelectKey节点的属性信息,构建MappedStatement,并添加 //configuration的mappedStatements的Map中Map<id-nameSpace,MappedStatement> builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, keyGenerator, keyProperty, null, databaseId, langDriver); //构造全局唯一命名空间 id = builderAssistant.applyCurrentNamespace(id, false); //从configuration的mappedStatements Map中,获取keyStatement MappedStatement keyStatement = configuration.getMappedStatement(id, false); //构建SelectKeyGenerator,并添加在configuration的keyGenerators-Map中 configuration.addKeyGenerator(id, new SelectKeyGenerator(keyStatement, executeBefore)); nodeToHandle.getParent().getNode().removeChild(nodeToHandle.getNode()); }
//configuration
//添加keyGenerators与其命名空间的映射关系到keyGenerators中
//keyGenerators:Map<nameSpace ,KeyGenerator>
public void addKeyGenerator(String id, KeyGenerator keyGenerator) { keyGenerators.put(id, keyGenerator); }
回到这一句
//根据select|insert|update|delete节点的属性信息,构建MappedStatement
//并添加到configuration的mappedStatements的Map中Map<id-nameSpace,MappedStatement>
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, langDriver);
//MapperBuilderAssistant
public MappedStatement addMappedStatement(String id, SqlSource sqlSource, StatementType statementType, SqlCommandType sqlCommandType, Integer fetchSize, Integer timeout, String parameterMap, Class parameterType, String resultMap, Class resultType, ResultSetType resultSetType, boolean flushCache, boolean useCache, boolean resultOrdered, KeyGenerator keyGenerator, String keyProperty, String keyColumn, String databaseId, LanguageDriver lang) { if(unresolvedCacheRef) { //如果缓存参考没有解决,则抛出IncompleteElementException throw new IncompleteElementException("Cache-ref not yet resolved"); } else { //获取全局nameSpace id = applyCurrentNamespace(id, false); boolean isSelect = sqlCommandType == SqlCommandType.SELECT; org.apache.ibatis.mapping.MappedStatement.Builder statementBuilder = new org.apache.ibatis.mapping.MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType); statementBuilder.resource(resource); statementBuilder.fetchSize(fetchSize); statementBuilder.statementType(statementType); statementBuilder.keyGenerator(keyGenerator); statementBuilder.keyProperty(keyProperty); statementBuilder.keyColumn(keyColumn); statementBuilder.databaseId(databaseId); statementBuilder.lang(lang); statementBuilder.resultOrdered(resultOrdered); setStatementTimeout(timeout, statementBuilder); setStatementParameterMap(parameterMap, parameterType, statementBuilder); setStatementResultMap(resultMap, resultType, resultSetType, statementBuilder); setStatementCache(isSelect, flushCache, useCache, currentCache, statementBuilder); //根据statement的节点信息,构造MappedStatement MappedStatement statement = statementBuilder.build(); //将statement,添加到configuration的mappedStatements的Map中 configuration.addMappedStatement(statement); return statement; } }
//MappedStatement
public final class MappedStatement { private String resource; private Configuration configuration; private String id; private Integer fetchSize; private Integer timeout; private StatementType statementType; private ResultSetType resultSetType; private SqlSource sqlSource; private Cache cache; private ParameterMap parameterMap; private List resultMaps; private boolean flushCacheRequired; private boolean useCache; private boolean resultOrdered; private SqlCommandType sqlCommandType; private KeyGenerator keyGenerator; private String keyProperties[]; private String keyColumns[]; private boolean hasNestedResultMaps; private String databaseId; private Log statementLog; private LanguageDriver lang; //MappedStatement的内部静态构造类 public static class Builder { public MappedStatement build() { if(!$assertionsDisabled && mappedStatement.configuration == null) throw new AssertionError(); if(!$assertionsDisabled && mappedStatement.id == null) throw new AssertionError(); if(!$assertionsDisabled && mappedStatement.sqlSource == null) throw new AssertionError(); if(!$assertionsDisabled && mappedStatement.lang == null) { throw new AssertionError(); } else { mappedStatement.resultMaps = Collections.unmodifiableList(mappedStatement.resultMaps); return mappedStatement; } } } //获取具体sql的包装类BoundSql public BoundSql getBoundSql(Object parameterObject) { BoundSql boundSql = sqlSource.getBoundSql(parameterObject); List parameterMappings = boundSql.getParameterMappings(); if(parameterMappings == null || parameterMappings.size() <= 0) boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject); Iterator i$ = boundSql.getParameterMappings().iterator(); do { if(!i$.hasNext()) break; ParameterMapping pm = (ParameterMapping)i$.next(); String rmId = pm.getResultMapId(); if(rmId != null) { //根据rmId从configuration获取对应的ResultMap ResultMap rm = configuration.getResultMap(rmId); if(rm != null) //设置hasNestedResultMaps属性 hasNestedResultMaps |= rm.hasNestedResultMaps(); } } while(true); return boundSql; } }
//BoundSql,sql的包装类
public class BoundSql { private String sql; private List parameterMappings; private Object parameterObject; private Map additionalParameters; private MetaObject metaParameters; public BoundSql(Configuration configuration, String sql, List parameterMappings, Object parameterObject) { this.sql = sql; this.parameterMappings = parameterMappings; this.parameterObject = parameterObject; additionalParameters = new HashMap(); metaParameters = configuration.newMetaObject(additionalParameters); } public String getSql() { return sql; } }
从上面可以看出,解析select|insert|update|delete-Xnode信息,首先将节点信息包装成XMLStatementBuilder,由XMLStatementBuilder,去解析,当XMLStatementBuilder解析时,statement节点Xnode的参考的缓存不存在,则抛出IncompleteElementException,则将XMLStatementBuilder添加到configuration的IncompleteStatement集合中,
LinkedList<XMLStatementBuilder>;如果缓存引用已解决,则解析SelectKey节点信息,
跟SelectKey节点的属性信息,构建keyStatement,并添加configuration的mappedStatements的Map中,Map<id-nameSpace,MappedStatement>,根据keyStatement,构建SelectKeyGenerator,并添加在configuration的keyGenerators-Map中,如果无SelectKey节点,则根据statement节点的useGeneratedKeys属性和全局配置信息isUseGeneratedKeys与SqlCommandType.INSERT产生对应的KeyGenerator;根据statement节点和KeyGenerator,构造MapperStatement,添加到configuration的mappedStatements的Map中。
//绑定Mapper的命名空间
bindMapperForNamespace();
private void bindMapperForNamespace() { //从MapperBuilderAssistant获取当前命名空间 String namespace = builderAssistant.getCurrentNamespace(); if(namespace != null) { Class boundType = null; try { //加载对应的namespace对应的Class boundType = Resources.classForName(namespace); } catch(ClassNotFoundException e) { } if(boundType != null && !configuration.hasMapper(boundType)) { //configuration,将资源信息,添加的loadedResources中Set<resource:nameSpace> configuration.addLoadedResource((new StringBuilder()).append("namespace:").append(namespace).toString()); // configuration.addMapper(boundType); } } }
//configuration,将资源信息,添加的loadedResources中Set<resource:nameSpace>
public void addLoadedResource(String resource) { loadedResources.add(resource); }
//mapperRegistry,注册mapInterface
public void addMapper(Class type) { mapperRegistry.addMapper(type); }
//MapperRegistry
public class MapperRegistry { private Configuration config; private final Map knownMappers = new HashMap(); public MapperRegistry(Configuration config) { this.config = config; } public void addMapper(Class type) { boolean loadCompleted; if(!type.isInterface()) break MISSING_BLOCK_LABEL_125; if(hasMapper(type)) throw new BindingException((new StringBuilder()).append("Type ").append(type).append(" is already known to the MapperRegistry.").toString()); loadCompleted = false; knownMappers.put(type, new MapperProxyFactory(type)); //根据mapInterface,Class和config构建MapperAnnotationBuilder MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type); parser.parse(); loadCompleted = true; if(!loadCompleted) knownMappers.remove(type); break MISSING_BLOCK_LABEL_125; Exception exception; exception; if(!loadCompleted) knownMappers.remove(type); throw exception; } }
//MapperRegistry
public class MapperRegistry { public void addMapper(Class type) { boolean loadCompleted; if(!type.isInterface()) break MISSING_BLOCK_LABEL_125; if(hasMapper(type)) throw new BindingException((new StringBuilder()).append("Type ").append(type).append(" is already known to the MapperRegistry.").toString()); loadCompleted = false; //添加Class与MapperProxyFactory的对应关系 knownMappers.put(type, new MapperProxyFactory(type)); //构造Mapperclass注解Builder类 MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type); //解析注解 parser.parse(); loadCompleted = true; if(!loadCompleted) knownMappers.remove(type); break MISSING_BLOCK_LABEL_125; Exception exception; exception; if(!loadCompleted) knownMappers.remove(type); throw exception; } private Configuration config; //HashMap<Class,MapperProxyFactory> private final Map knownMappers = new HashMap(); } //MapperProxyFactory,mapperInterface的代理工厂 public class MapperProxyFactory { public MapperProxyFactory(Class mapperInterface) { methodCache = new ConcurrentHashMap(); this.mapperInterface = mapperInterface; } protected Object newInstance(MapperProxy mapperProxy) { //代理生成实例 return Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); } public Object newInstance(SqlSession sqlSession) { MapperProxy mapperProxy = new MapperProxy(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); } private final Class mapperInterface; private Map methodCache; }
//MapperProxy
public class MapperProxy implements InvocationHandler, Serializable { public MapperProxy(SqlSession sqlSession, Class mapperInterface, Map methodCache) { this.sqlSession = sqlSession; this.mapperInterface = mapperInterface; this.methodCache = methodCache; } public Object invoke(Object proxy, Method method, Object args[]) throws Throwable { if(java/lang/Object.equals(method.getDeclaringClass())) { return method.invoke(this, args); } else { MapperMethod mapperMethod = cachedMapperMethod(method); return mapperMethod.execute(sqlSession, args); } } private MapperMethod cachedMapperMethod(Method method) { MapperMethod mapperMethod = (MapperMethod)methodCache.get(method); if(mapperMethod == null) { mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()); methodCache.put(method, mapperMethod); } return mapperMethod; } private static final long serialVersionUID = -6424540398559729838L; private final SqlSession sqlSession; private final Class mapperInterface; //Map<Method,MapperMethod>,即二级缓存 private final Map methodCache; }
//MapperMethod
public class MapperMethod { //方法签名 public static class MethodSignature{ private final boolean returnsMany; private final boolean returnsMap; private final boolean returnsVoid; private final Class returnType; private final String mapKey; private final Integer resultHandlerIndex; private final Integer rowBoundsIndex; private final SortedMap params; private final boolean hasNamedParameters; public MethodSignature(Configuration configuration, Method method) throws BindingException { returnType = method.getReturnType(); returnsVoid = Void.TYPE.equals(returnType); returnsMany = configuration.getObjectFactory().isCollection(returnType) || returnType.isArray(); mapKey = getMapKey(method); returnsMap = mapKey != null; hasNamedParameters = hasNamedParams(method); rowBoundsIndex = getUniqueParamIndex(method, org/apache/ibatis/session/RowBounds); resultHandlerIndex = getUniqueParamIndex(method, org/apache/ibatis/session/ResultHandler); params = Collections.unmodifiableSortedMap(getParams(method, hasNamedParameters)); } } //statement类型,SqlCommand public static class SqlCommand { private final String name; private final SqlCommandType type; } //参数Map public static class ParamMap extends HashMap { public Object get(Object key) { if(!super.containsKey(key)) throw new BindingException((new StringBuilder()).append("Parameter '").append(key).append("' not found. Available parameters are ").append(keySet()).toString()); else return super.get(key); } private static final long serialVersionUID = -2212268410512043556L; public ParamMap() { } } //method执行方法 public Object execute(SqlSession sqlSession, Object args[]) { Object result; //插入 if(SqlCommandType.INSERT == command.getType()) { //将参数转换为SqlCommand对应的参数 Object param = method.convertArgsToSqlCommandParam(args); //执行插入,并包装返回结果 result = rowCountResult(sqlSession.insert(command.getName(), param)); } else //更新 if(SqlCommandType.UPDATE == command.getType()) { //执行更新,并包装返回结果 Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.update(command.getName(), param)); } else //删除 if(SqlCommandType.DELETE == command.getType()) { //执行删除,并包装返回结果 Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.delete(command.getName(), param)); } else //查询 if(SqlCommandType.SELECT == command.getType()) { if(method.returnsVoid() && method.hasResultHandler()) { //无返回结果 executeWithResultHandler(sqlSession, args); result = null; } else if(method.returnsMany()) //返回结果为List result = executeForMany(sqlSession, args); else if(method.returnsMap()) { //返回结果为Map result = executeForMap(sqlSession, args); } else { //返回结果为Object Object param = method.convertArgsToSqlCommandParam(args); result = sqlSession.selectOne(command.getName(), param); } } else { throw new BindingException((new StringBuilder()).append("Unknown execution method for: ").append(command.getName()).toString()); } if(result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) throw new BindingException((new StringBuilder()).append("Mapper method '").append(command.getName()).append(" attempted to return null from a method with a primitive return type (").append(method.getReturnType()).append(").").toString()); else return result; } //包装返回结果 private Object rowCountResult(int rowCount) { Object result; if(method.returnsVoid()) result = null; else if(java/lang/Integer.equals(method.getReturnType()) || Integer.TYPE.equals(method.getReturnType())) result = Integer.valueOf(rowCount); else if(java/lang/Long.equals(method.getReturnType()) || Long.TYPE.equals(method.getReturnType())) result = Long.valueOf(rowCount); else if(java/lang/Boolean.equals(method.getReturnType()) || Boolean.TYPE.equals(method.getReturnType())) result = Boolean.valueOf(rowCount > 0); else throw new BindingException((new StringBuilder()).append("Mapper method '").append(command.getName()).append("' has an unsupported return type: ").append(method.getReturnType()).toString()); return result; } //无返回结果 private void executeWithResultHandler(SqlSession sqlSession, Object args[]) { MappedStatement ms = sqlSession.getConfiguration().getMappedStatement(command.getName()); if(Void.TYPE.equals(((ResultMap)ms.getResultMaps().get(0)).getType())) throw new BindingException((new StringBuilder()).append("method ").append(command.getName()).append(" needs either a @ResultMap annotation, a @ResultType annotation,").append(" or a resultType attribute in XML so a ResultHandler can be used as a parameter.").toString()); Object param = method.convertArgsToSqlCommandParam(args); if(method.hasRowBounds()) { RowBounds rowBounds = method.extractRowBounds(args); sqlSession.select(command.getName(), param, rowBounds, method.extractResultHandler(args)); } else { sqlSession.select(command.getName(), param, method.extractResultHandler(args)); } } //返回结果为List private Object executeForMany(SqlSession sqlSession, Object args[]) { Object param = method.convertArgsToSqlCommandParam(args); List result; if(method.hasRowBounds()) { RowBounds rowBounds = method.extractRowBounds(args); result = sqlSession.selectList(command.getName(), param, rowBounds); } else { result = sqlSession.selectList(command.getName(), param); } if(!method.getReturnType().isAssignableFrom(result.getClass())) { if(method.getReturnType().isArray()) return ((Object) (convertToArray(result))); else return convertToDeclaredCollection(sqlSession.getConfiguration(), result); } else { return result; } } //返回结果为Map private Map executeForMap(SqlSession sqlSession, Object args[]) { Object param = method.convertArgsToSqlCommandParam(args); Map result; if(method.hasRowBounds()) { RowBounds rowBounds = method.extractRowBounds(args); result = sqlSession.selectMap(command.getName(), param, method.getMapKey(), rowBounds); } else { result = sqlSession.selectMap(command.getName(), param, method.getMapKey()); } return result; } private final SqlCommand command;//method,对应的statement的描述 private final MethodSignature method;//方法签名 }
从上可以看出Configuration添加MapperInterface,就是MapperRegistry注册到其
HashMap<Class,MapperProxyFactory>中,MapperProxyFactory是MapperInterface的代理,
生成MapperInterface的MapperProxy代理实例,MapperProxy中利用Map<Method,MapperMethod>,
实现二级缓存;MapperInterface执行DML实际上是,通过MapperProxy反射,调用MapperMethod的方法。
//Resources
public class Resources { public static Class classForName(String className) throws ClassNotFoundException { return classLoaderWrapper.classForName(className); } private static ClassLoaderWrapper classLoaderWrapper = new ClassLoaderWrapper(); private static Charset charset; }
//从configuration中移除未处理完成的ResultMaps
parsePendingResultMaps();
private void parsePendingResultMaps() { Collection incompleteResultMaps = configuration.getIncompleteResultMaps(); synchronized(incompleteResultMaps) { for(Iterator iter = incompleteResultMaps.iterator(); iter.hasNext();) try { //解决ResultMap依赖问题extend ((ResultMapResolver)iter.next()).resolve(); //从configuration的IncompleteResultMap中移除 iter.remove(); } catch(IncompleteElementException e) { } } }
//从configuration中移除未完成的CacheRefs
parsePendingChacheRefs();
private void parsePendingChacheRefs() { Collection incompleteCacheRefs = configuration.getIncompleteCacheRefs(); synchronized(incompleteCacheRefs) { for(Iterator iter = incompleteCacheRefs.iterator(); iter.hasNext();) try { //CacheRefResolver的参考缓存可以在configuration的缓存中找到, //则从IncompleteCacheRefs,LinkedList<CacheRefResolver>中移除CacheRefResolver ((CacheRefResolver)iter.next()).resolveCacheRef(); iter.remove(); } catch(IncompleteElementException e) { } } }
//从configuration中移除未完成的Statements
parsePendingStatements();
private void parsePendingStatements() { Collection incompleteStatements = configuration.getIncompleteStatements(); synchronized(incompleteStatements) { for(Iterator iter = incompleteStatements.iterator(); iter.hasNext();) try { //重新解析statement节点信息,完成后从incompleteStatements,移除 ((XMLStatementBuilder)iter.next()).parseStatementNode(); iter.remove(); } catch(IncompleteElementException e) { } } }
总结:
解析Mapper对应的xml文件,实际上是解析xml的mapper Xnode,具体到namespace属性,及cache,cache-ref,parameterMap,resultMap,sql,及select|insert|update|delete子节点,当解析完mapper Xnode时,将Mapper的资源id,
添加configuration的Set<class.name> resource;然后绑定Mapper的命名空间,实际做的是:通过Configuration的MapperRegistry,注册到MapperRegistry的HashMap<Class,MapperProxyFactory>中,MapperProxyFactory是MapperInterface的代理,
生成MapperInterface的MapperProxy代理实例,MapperProxy中利用Map<Method,MapperMethod>,实现二级缓存,MapperInterface执行DML实际上是,通过MapperProxy反射,调用MapperMethod的方法;然后处理未完成的ResultMap,
CacheRefs,Statements解析处理任务,完成后,从configuration中未完成IncompleteResultMaps、CacheRefs、StatementsParser中移除任务。
各小节总结:
cache-ref:
从分析配置cache-ref,实际上,将cache和cache-ref的命名空间的映射关系添加到configuration中,并从configuration的获取cacheRefNamespace对应的Cache,如果cache-ref的cacheRefNamespace对应的缓存,不存在,则抛出IncompleteElementException,并将对应的CacheRefResolver添加到configuration的IncompleteCacheRef集合中Linklist<CacheRefResolver>;
cache:
从上的分析可以看出Cache的节点的解析,实际上是,获取cache节点的type对应的Class,
cache节点的eviction对应的缓存算法Class,以及刷新间隔,读写属性,构造CacheBuilder
,并添加的configuration的二级缓存StrictMap<nameSpace,CacheBuilder>;
parameterMap:
从上的分析可以看出ParameterMap的解析实际是解析ParameterMap的id,type属性和
parameter子节点;然后解析parameter的property,javaType,jdbcType,typeHalder,resultMap的属性,根据这些属性构建parameterMapping,并添加的parameterMappings(ArrayList<ParameterMapping>)集合中;
然后再根据id,type属性和parameterMappings,构造ParameterMap,并添加到configuration的parameterMaps中;
resultMap:
从以上分析可以看出resultMap节点的解析,首先获取resultMap的id,type等属性,再处理其子节点result,constructor,discriminator;对于result节点,解析column,property,jdbcType等属性,包装成ResultMapping,添加resultMappings集合中ArrayList<ResultMapping>;最后根据resultMap的id,type等属性和
resultMappings构建ResultMap,如果extend的父ResultMap不存在,则抛出IncompleteElementException,并添加到configuration
的,IncompleteResultMap-LinkedList<ResultMapResolver>中,如果存在则,添加的configuration的resultMaps中;
Sql:
从上可以看出解析Sql节点是将Sql节点对应Xnode与id映射关系,添加到sqlFragments-HashMap<id,XNode>中;
select|insert|update|delete:
从上面可以看出,解析select|insert|update|delete-Xnode信息,首先将节点信息包装成XMLStatementBuilder,由XMLStatementBuilder,去解析,当XMLStatementBuilder解析时,statement节点Xnode的参考的缓存不存在,则抛出IncompleteElementException,则将XMLStatementBuilder添加到configuration的IncompleteStatement集合中,
LinkedList<XMLStatementBuilder>;如果缓存引用已解决,则解析SelectKey节点信息,
跟SelectKey节点的属性信息,构建keyStatement,并添加configuration的mappedStatements的Map中,Map<id-nameSpace,MappedStatement>,根据keyStatement,构建SelectKeyGenerator,并添加在configuration的keyGenerators-Map中,如果无SelectKey节点,则根据statement节点的useGeneratedKeys属性和全局配置信息isUseGeneratedKeys与SqlCommandType.INSERT产生对应的KeyGenerator;根据statement节点和KeyGenerator,构造MapperStatement,添加到configuration的mappedStatements的Map中。
//SqlCommandType
public final class SqlCommandType extends Enum { public static final SqlCommandType UNKNOWN; public static final SqlCommandType INSERT; public static final SqlCommandType UPDATE; public static final SqlCommandType DELETE; public static final SqlCommandType SELECT; private static final SqlCommandType $VALUES[]; static { UNKNOWN = new SqlCommandType("UNKNOWN", 0); INSERT = new SqlCommandType("INSERT", 1); UPDATE = new SqlCommandType("UPDATE", 2); DELETE = new SqlCommandType("DELETE", 3); SELECT = new SqlCommandType("SELECT", 4); $VALUES = (new SqlCommandType[] { UNKNOWN, INSERT, UPDATE, DELETE, SELECT }); } }
//StatementTypes
public final class StatementType extends Enum { public static final StatementType STATEMENT; public static final StatementType PREPARED; public static final StatementType CALLABLE; private static final StatementType $VALUES[]; static { STATEMENT = new StatementType("STATEMENT", 0); PREPARED = new StatementType("PREPARED", 1); CALLABLE = new StatementType("CALLABLE", 2); $VALUES = (new StatementType[] { STATEMENT, PREPARED, CALLABLE }); } }