- 浏览: 985059 次
文章分类
- 全部博客 (428)
- Hadoop (2)
- HBase (1)
- ELK (1)
- ActiveMQ (13)
- Kafka (5)
- Redis (14)
- Dubbo (1)
- Memcached (5)
- Netty (56)
- Mina (34)
- NIO (51)
- JUC (53)
- Spring (13)
- Mybatis (17)
- MySQL (21)
- JDBC (12)
- C3P0 (5)
- Tomcat (13)
- SLF4J-log4j (9)
- P6Spy (4)
- Quartz (12)
- Zabbix (7)
- JAVA (9)
- Linux (15)
- HTML (9)
- Lucene (0)
- JS (2)
- WebService (1)
- Maven (4)
- Oracle&MSSQL (14)
- iText (11)
- Development Tools (8)
- UTILS (4)
- LIFE (8)
最新评论
-
Donald_Draper:
Donald_Draper 写道刘落落cici 写道能给我发一 ...
DatagramChannelImpl 解析三(多播) -
Donald_Draper:
刘落落cici 写道能给我发一份这个类的源码吗Datagram ...
DatagramChannelImpl 解析三(多播) -
lyfyouyun:
请问楼主,执行消息发送的时候,报错:Transport sch ...
ActiveMQ连接工厂、连接详解 -
ezlhq:
关于 PollArrayWrapper 状态含义猜测:参考 S ...
WindowsSelectorImpl解析一(FdMap,PollArrayWrapper) -
flyfeifei66:
打算使用xmemcache作为memcache的客户端,由于x ...
Memcached分布式客户端(Xmemcached)
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 }); } }
发表评论
-
Mybatis缓存实现
2016-12-07 10:36 983SqlSessionFactory初始化:http://don ... -
DefaultSqlSession第三讲-事务提交,回滚,关闭SqlSession,清除缓存
2016-11-20 11:07 5715上面两篇讲过query和update及flushStateme ... -
DefaultSqlSession第二讲-更新,刷新Statement
2016-11-20 11:06 635上一篇文章中,我们讲到DefaultSqlSession的查询 ... -
DefaultSqlSession第一讲query解析
2016-11-20 11:06 1632上一篇文章:我们说过DefaultSqlSession,Def ... -
Mybatis的SqlSession解析
2016-11-20 11:02 2567在前文中,Mybatis使用教程中,有下面一段代码: Sql ... -
Mybatis的Reflector解析
2016-11-18 12:53 2166Mybatis的MetaObject解析:http://don ... -
Mybatis的MetaObject解析
2016-11-18 11:40 9585SqlSessionFactory初始化:http://don ... -
mybatis 动态标签语句的解析(BoundSql)
2016-10-30 09:48 5767SqlSessionFactory初始化:http://don ... -
Mybatis的Environment解析详解
2016-10-29 18:28 1998SqlSessionFactory初始化:http://don ... -
Mybatis 解析Mapper(class)
2016-10-26 11:44 3369SqlSessionFactory初始化:http://don ... -
Mybatis加载解析Mapper(xml)文件第一讲
2016-10-25 16:51 6203SqlSessionFactory初始化:http://don ... -
SqlSessionFactory初始化
2016-10-20 15:38 2463mybatis 使用教程:http://donald-drap ... -
mybatis 使用教程
2016-10-14 09:03 915Myeclispe下mybatis generator的使 ... -
Spring+Mybatis多数据源的实现
2016-09-21 18:15 3097浅谈Spring事务隔离级别:http://www.cnblo ... -
mybaitis CDATA 防止字符被解析
2016-08-17 18:45 727在使用mybatis 时我们sql是写在xml 映射文件中,如 ... -
Myeclispe下mybatis generator的使用
2016-07-05 18:05 1380准备:下载附件包解压到myeclispe的dropins文件夹 ...
相关推荐
1. 加载配置并初始化:MyBatis首先加载配置文件,将SQL配置信息转化为MappedStatement对象存储在内存中。 2. 接收调用请求:调用MyBatis提供的API,传入SQL的ID和参数对象。 3. 处理操作请求:根据SQL的ID找到对应的...
2. **MyBatis-SQLMapClient**:这部分提供了对XML配置文件的处理,用于读取和解析Mapper配置。 3. **MyBatis-Plus**(可选):这是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提高...
二、XML映射文件解析 Mybatis的XML映射文件是定义SQL语句和结果映射的关键。手写这部分需要实现XML解析,通常使用DOM解析器来读取和解析XML文件。 1. 加载XML文件:使用Java的`javax.xml.parsers....
### MyBatis 第二天课堂笔记精要 #### 一、MyBatis 框架简介及应用场景 **1.1 MyBatis 的定义** MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。尽管 MyBatis 提供了一定程度的对象...
2. **Mapper接口**:定义了与XML文件中的SQL语句对应的Java方法。 3. **实体类**:代表数据库表的记录,包含表字段对应的属性和getter/setter方法。 4. **DAO接口**:提供调用Mapper接口的方法,便于业务层使用。 ...
- **Maven 方式**:在项目的 `pom.xml` 文件中添加 MyBatis 的依赖。 ```xml <groupId>org.mybatis <artifactId>mybatis <version>3.3.0 ``` - **非 Maven 方式**:将 mybatis-x.x.x.jar 文件直接添加到...
"01-Mybatis10-第一个mybatis程序"涵盖了Mybatis的基本使用步骤,包括配置Mybatis的主配置文件(mybatis-config.xml)、创建Mapper接口、编写Mapper XML文件以及实体类。在实际运行时,Mybatis会加载配置文件,根据...
4. Mapper配置:通过在Java类路径下的mybatis目录下放置Mapper XML文件,或者使用注解式Mapper,可以方便地定义SQL语句。 五、实战演练 1. 创建Spring Boot项目:首先创建一个基于Spring Boot的新项目,并在pom.xml...
**第二步:配置POM.xml** 在`pom.xml`文件中,我们需要引入SpringBoot的父POM和相关依赖。这包括SpringBoot的起步依赖(`spring-boot-starter-jdbc`),MyBatis的SpringBoot起步依赖(`mybatis-spring-boot-starter...
3. **Mapper接口与XML配置**:解析Mapper接口和对应的XML配置文件,理解SQL语句如何在XML中编写,以及如何通过注解方式实现映射。 4. **基本 CRUD 操作**:展示如何使用MyBatis执行增删改查操作,包括动态SQL和结果...
MyBatis将SQL语句分离到mapper.xml文件中,使得SQL和Java代码解耦,方便修改。 - **参数传递**:JDBC传递参数繁琐,MyBatis通过动态SQL和参数映射简化这一过程,能够自动将Java对象转化为SQL语句的参数。 - **结果...
根据提供的文件信息,本次将对MyBatis框架的相关知识点进行深入解析。MyBatis是一款优秀的持久层框架,它支持自定义SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集,通过...
MyBatis中,我们可以通过Mapper接口和XML配置文件来编写SQL语句,包括分页查询。传统的分页查询通常需要在SQL语句中添加LIMIT和OFFSET子句,但在大数据量的情况下,OFFSET的性能会随着偏移量的增长而急剧下降。为了...
**Mapper 的 XML 配置文件** 详细介绍了如何通过 XML 文件配置 MyBatis 的各种元素。 - **属性(properties)**: - **定义**:用来设置全局配置属性,如数据库连接的 URL、用户名和密码等。 - **设置方式**:可...
- **第二步**:使用Java类生成mapper文件。 - **第三步**:拷贝生成的mapper文件到工程中指定的目录中。 - **Mapper.xml**:生成的映射文件。 - **Mapper.java**:生成的接口文件。 - **第四步Mapper接口测试**:...
- **XML映射文件配置**:在Mapper XML文件中,使用`<association>`和`<collection>`元素来定义多对多关系。`<collection>`元素用于表示一对多或多对多关系,而`<association>`则表示一对一或多对一关系。 - **注解...
MyBatis 的动态 SQL 是通过 XML 映射文件中的特定标签实现的,如 trim、where、set、foreach、if、choose、when、otherwise、bind 等。这些标签能够帮助我们在运行时根据条件动态地拼接 SQL 语句,其执行原理是利用 ...
4. 整合MyBatis与Spring:使用Spring的SqlSessionFactoryBean加载MyBatis的配置,将Mapper接口与XML映射文件关联。 5. 测试:编写JUnit测试用例,确保SSM框架整合成功,各个组件能正常工作。 在实际开发中,我们...
- MyBatis的缓存机制简单,而Hibernate的缓存机制更为复杂,支持第二级缓存和查询缓存。 - MyBatis的延迟加载只限于关联对象,而Hibernate提供全局的延迟加载。 在面试中,除了这些基础知识,还需要了解MyBatis的...
2. **Mapper接口与XML文件未正确关联**: - Mapper接口中的方法名与XML文件中定义的ID不一致。 - XML文件中声明的方法ID拼写错误。 3. **Mapper接口未被正确注册**: - 如果使用了Spring框架,确保Mapper接口被...