Mybatis加载解析Mapper(xml)文件第一讲
程序员文章站
2022-05-09 22:32:57
...
SqlSessionFactory初始化:http://donald-draper.iteye.com/blog/2331917
Mybatis加载解析Mapper(xml)文件第二讲:http://donald-draper.iteye.com/blog/2333191
在上篇 SqlSessionFactory初始化中,解析全局配置文件mybatisConfig.xml文件时,讲到,properties,typeAliases,plugins,objectFactory,objectWrapperFactory
,settings,environments,databaseIdProvider,typeHandlers的初始化,而mappers的初始化较复杂,
我们放在这一篇来讲。
首先从下面这个方法来看
//加载Mapper xml文件,并解析
//XMLMapperBuilder
//Configuration,添加Mapper xml文件名到Set<String> loadedResources;
//其中key为class完整名,com.mapper.UserMapper
//XPathParser
下面分别来看根据mapper Xnode 配置,namespace,cache,cacheref,parameterMap,resultMap,sql,及select|insert|update|delete子节点
//配置namespace
从上面的方法可以看出,命名空间实际上是配置Mapper对应的MapperBuilderAssistantcurrentNamespace属性
//配置cache-ref
cacheRefElement(context.evalNode("cache-ref"));
//configuration
//CacheRefResolver,缓存参考处理器
//MapperBuilderAssistant,
从分析配置cache-ref,实际上,将cache和cache-ref的命名空间的映射关系添加到configuration中,并从configuration的获取cacheRefNamespace对应的Cache,如果cache-ref的cacheRefNamespace对应的缓存,不存在,则抛出IncompleteElementException,并将对应的CacheRefResolver添加到configuration的IncompleteCacheRef集合中Linklist<CacheRefResolver>;
//配置cache
cacheElement(context.evalNode("cache"));
配置实例
//XNode
//返回Xnode的name属性值,不存在返回默认值
//TypeAliasRegistry 根据type,从TypeAliasRegistry的TYPE_ALIASES中获取对应的Class
// private final HashMap TYPE_ALIASES = new HashMap();
//HashMap<alias,Class> key为Class对应的别名alias
//MapperBuilderAssistant
//将缓存添加到Configuration的二级缓存中
//Configuration
//将缓存添加到Configuration的二级缓存中
//StrictMap<currentNamespace,CacheBuilder>
//caches = new StrictMap("Caches collection");
//BaseBuilder
从上的分析可以看出Cache的节点的解析,实际上是,获取cache节点的type对应的Class,
cache节点的eviction对应的缓存算法Class,以及刷新间隔,读写属性,构造CacheBuilder
,并添加的configuration的二级缓存StrictMap<nameSpace,CacheBuilder>
//CacheBuilder
//MetaObject,设置Class实例属性
这个我们在后面单讲
//配置parameterMap
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
parameterMap配置实例
//MapperBuilderAssistant
//configuration
//ParameterMap的映射关系到configuration的parameterMaps中
//parameterMaps = new StrictMap("Parameter Maps collection");
//Map<nameSpace,ParameterMap>
//ParameterMapping,ParameterMap的参数映射描述
//ParameterMode
//ParameterMap
//从configuration中移除未完成的ChacheRefs
parsePendingChacheRefs();
从上的分析可以看出ParameterMap的解析实际是解析ParameterMap的id,type属性和
parameter子节点;然后解析parameter的property,javaType,jdbcType,typeHalder,
resultMap的属性根据这些属性构建parameterMapping,并添加的parameterMappings(ArrayList<ParameterMapping>)集合中;然后再根据id,type属性和parameterMappings,构造ParameterMap,并添加到configuration的parameterMaps中
。
总结:
解析Mapper对应的xml文件,实际上是解析xml的mapper Xnode,具体到namespace属性,及cache,cache-ref,parameterMap,篇幅有限这一篇我们讲到namespace属性,及cache,cache-ref,parameterMap,这三部分的解析,我们都有小节,实际上就是将这些添加configuration的相应的cache,parameterMap的StrictMap中。
各小节的总结:
namespace:
从上面的方法可以看出,命名空间实际上是配置Mapper对应的MapperBuilderAssistantcurrentNamespace属性;
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,sql,及select|insert|update|delete子节点
//XMLMapperEntityResolver
Mybatis加载解析Mapper(xml)文件第二讲:http://donald-draper.iteye.com/blog/2333191
在上篇 SqlSessionFactory初始化中,解析全局配置文件mybatisConfig.xml文件时,讲到,properties,typeAliases,plugins,objectFactory,objectWrapperFactory
,settings,environments,databaseIdProvider,typeHandlers的初始化,而mappers的初始化较复杂,
我们放在这一篇来讲。
首先从下面这个方法来看
//加载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); }
//XPathParser
public class XPathParser { private Document document; private boolean validation; private EntityResolver entityResolver; private Properties variables; private XPath xpath; //构造XPathParser public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) { commonConstructor(validation, variables, entityResolver); document = createDocument(new InputSource(inputStream)); } //初始化属性 private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) { this.validation = validation; this.entityResolver = entityResolver; this.variables = variables; XPathFactory factory = XPathFactory.newInstance(); xpath = factory.newXPath(); } //创建createDocument private Document createDocument(InputSource inputSource) { DocumentBuilder builder; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(validation); factory.setNamespaceAware(false); factory.setIgnoringComments(true); factory.setIgnoringElementContentWhitespace(false); factory.setCoalescing(false); factory.setExpandEntityReferences(true); builder = factory.newDocumentBuilder(); builder.setEntityResolver(entityResolver); builder.setErrorHandler(new ErrorHandler() { public void error(SAXParseException exception) throws SAXException { throw exception; } public void fatalError(SAXParseException exception) throws SAXException { throw exception; } public void warning(SAXParseException saxparseexception) throws SAXException { } final XPathParser this$0; { this$0 = XPathParser.this; super(); } }); return builder.parse(inputSource); Exception e; e; throw new BuilderException((new StringBuilder()).append("Error creating document instance. Cause: ").append(e).toString(), e); } public XNode evalNode(String expression) { return evalNode(document, expression); } public Integer evalInteger(String expression) { return evalInteger(document, expression); } }
下面分别来看根据mapper Xnode 配置,namespace,cache,cacheref,parameterMap,resultMap,sql,及select|insert|update|delete子节点
//配置namespace
String namespace = context.getStringAttribute("namespace"); builderAssistant.setCurrentNamespace(namespace);
public class MapperBuilderAssistant extends BaseBuilder { private String currentNamespace;//命名空间 private String resource;//Mapper xml的url private Cache currentCache; private boolean unresolvedCacheRef; public MapperBuilderAssistant(Configuration configuration, String resource) { super(configuration); ErrorContext.instance().resource(resource); this.resource = resource; } //设置命名空间 public void setCurrentNamespace(String currentNamespace) { if(currentNamespace == null) throw new BuilderException("The mapper element requires a namespace attribute to be specified."); if(this.currentNamespace != null && !this.currentNamespace.equals(currentNamespace)) { throw new BuilderException((new StringBuilder()).append("Wrong namespace. Expected '").append(this.currentNamespace).append("' but found '").append(currentNamespace).append("'.").toString()); } else { this.currentNamespace = currentNamespace; return; } } }
从上面的方法可以看出,命名空间实际上是配置Mapper对应的MapperBuilderAssistantcurrentNamespace属性
//配置cache-ref
cacheRefElement(context.evalNode("cache-ref"));
private void cacheRefElement(XNode context) { if(context != null) { //添加cacheRef的命名空间映射关系 configuration.addCacheRef(builderAssistant.getCurrentNamespace(), context.getStringAttribute("namespace")); CacheRefResolver cacheRefResolver = new CacheRefResolver(builderAssistant, context.getStringAttribute("namespace")); try { //确定configuration中是否存在参考缓存 cacheRefResolver.resolveCacheRef(); } catch(IncompleteElementException e) { //如果参考缓存不存在,则将cacheRefResolver,添加到configuration //IncompleteCacheRef集合中Linklist<CacheRefResolver> configuration.addIncompleteCacheRef(cacheRefResolver); } } }
//configuration
public void addCacheRef(String namespace, String referencedNamespace) { //将CacheRef的namespace引用的referencedNamespace的映射关系,添加到 //configuration的缓存参考引用中cacheRefMap cacheRefMap.put(namespace, referencedNamespace); }
//CacheRefResolver,缓存参考处理器
public class CacheRefResolver { public CacheRefResolver(MapperBuilderAssistant assistant, String cacheRefNamespace) { this.assistant = assistant; this.cacheRefNamespace = cacheRefNamespace; } public Cache resolveCacheRef() { return assistant.useCacheRef(cacheRefNamespace); } private final MapperBuilderAssistant assistant; private final String cacheRefNamespace;//参考缓存命名空间 }
//MapperBuilderAssistant,
public Cache useCacheRef(String namespace) { if(namespace == null) throw new BuilderException("cache-ref element requires a namespace attribute."); Cache cache; unresolvedCacheRef = true; //根据命名空间,从configuration而级缓存中,获取缓存 cache = configuration.getCache(namespace); if(cache == null) throw new IncompleteElementException((new StringBuilder()).append("No cache for namespace '").append(namespace).append("' could be found.").toString()); //从这里可以看出,参考命名的缓存必须存在,否则抛出异常 currentCache = cache; unresolvedCacheRef = false; return cache; IllegalArgumentException e; e; throw new IncompleteElementException((new StringBuilder()).append("No cache for namespace '").append(namespace).append("' could be found.").toString(), e); }
从分析配置cache-ref,实际上,将cache和cache-ref的命名空间的映射关系添加到configuration中,并从configuration的获取cacheRefNamespace对应的Cache,如果cache-ref的cacheRefNamespace对应的缓存,不存在,则抛出IncompleteElementException,并将对应的CacheRefResolver添加到configuration的IncompleteCacheRef集合中Linklist<CacheRefResolver>;
//配置cache
cacheElement(context.evalNode("cache"));
配置实例
<!-- <cache eviction="LRU" flushInterval="60000" size="1024" readOnly="true" /> eviction是缓存的淘汰算法,可选值有"LRU"、"FIFO"、"SOFT"、"WEAK",缺省值是LRU flashInterval指缓存过期时间,单位为毫秒,60000即为60秒,缺省值为空,即只要容量足够,永不过期 size指缓存多少个对象,默认值为1024 readOnly是否只读,如果为true,则所有相同的sql语句返回的是同一个对象 (有助于提高性能,但并发操作同一条数据时,可能不安全), 如果设置为false,则相同的sql,后面访问的是cache的clone副本。 -->
private void cacheElement(XNode context) throws Exception { if(context != null) { //返回cache节点的type属性,不存在,则返回PERPETUAL String type = context.getStringAttribute("type", "PERPETUAL"); //根据type,从TypeAliasRegistry的TYPE_ALIASES中获取对应的Class Class typeClass = typeAliasRegistry.resolveAlias(type); //返回cache节点的eviction属性,不存在,则返回LRU, //eviction是缓存的淘汰算法,可选值有"LRU"、"FIFO"、"SOFT"、"WEAK",缺省值是LRU String eviction = context.getStringAttribute("eviction", "LRU"); //根据eviction,从TypeAliasRegistry的TYPE_ALIASES中获取对应的Class Class evictionClass = typeAliasRegistry.resolveAlias(eviction); Long flushInterval = context.getLongAttribute("flushInterval"); Integer size = context.getIntAttribute("size"); //返回cache节点的readOnly属性,不存在,则返回false, boolean readWrite = !context.getBooleanAttribute("readOnly", Boolean.valueOf(false)).booleanValue(); //获取缓存的child属性配置 java.util.Properties props = context.getChildrenAsProperties(); // builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, props); } }
//XNode
//返回Xnode的name属性值,不存在返回默认值
public String getStringAttribute(String name, String def) { String value = attributes.getProperty(name); if(value == null) return def; else return value; }
//TypeAliasRegistry 根据type,从TypeAliasRegistry的TYPE_ALIASES中获取对应的Class
// private final HashMap TYPE_ALIASES = new HashMap();
//HashMap<alias,Class> key为Class对应的别名alias
public Class resolveAlias(String string) { if(string == null) return null; Class value; String key = string.toLowerCase(Locale.ENGLISH); if(TYPE_ALIASES.containsKey(key)) value = (Class)TYPE_ALIASES.get(key); else value = Resources.classForName(string); return value; ClassNotFoundException e; e; throw new TypeException((new StringBuilder()).append("Could not resolve type alias '").append(string).append("'. Cause: ").append(e).toString(), e); }
//MapperBuilderAssistant
//将缓存添加到Configuration的二级缓存中
public Cache useNewCache(Class typeClass, Class evictionClass, Long flushInterval, Integer size, boolean readWrite, Properties props) { //获取缓存类型 typeClass = (Class)valueOrDefault(typeClass, org/apache/ibatis/cache/impl/PerpetualCache); //获取缓存算法类型 evictionClass = (Class)valueOrDefault(evictionClass, org/apache/ibatis/cache/decorators/LruCache); //构建缓存 Cache cache = (new CacheBuilder(currentNamespace)).implementation(typeClass).addDecorator(evictionClass).clearInterval(flushInterval).size(size).readWrite(readWrite).properties(props).build(); //将缓存添加到Configuration的二级缓存中 configuration.addCache(cache); currentCache = cache; return cache; }
//Configuration
//将缓存添加到Configuration的二级缓存中
//StrictMap<currentNamespace,CacheBuilder>
//caches = new StrictMap("Caches collection");
public void addCache(Cache cache) { caches.put(cache.getId(), cache); }
public class MapperBuilderAssistant extends BaseBuilder
//BaseBuilder
public abstract class BaseBuilder { protected final Configuration configuration; protected final TypeAliasRegistry typeAliasRegistry; protected final TypeHandlerRegistry typeHandlerRegistry; public BaseBuilder(Configuration configuration) { this.configuration = configuration; typeAliasRegistry = this.configuration.getTypeAliasRegistry(); typeHandlerRegistry = this.configuration.getTypeHandlerRegistry(); } //返回别名对应的Class类型 protected Class resolveAlias(String alias) { return typeAliasRegistry.resolveAlias(alias); } //返回别名对应的Class类型 protected Class resolveClass(String alias) { if(alias == null) return null; return resolveAlias(alias); Exception e; e; throw new BuilderException((new StringBuilder()).append("Error resolving class. Cause: ").append(e).toString(), e); } //根据别名创建实例 protected Object createInstance(String alias) { Class clazz = resolveClass(alias); if(clazz == null) return null; return resolveClass(alias).newInstance(); Exception e; e; throw new BuilderException((new StringBuilder()).append("Error creating instance. Cause: ").append(e).toString(), e); } protected Boolean booleanValueOf(String value, Boolean defaultValue) { return value != null ? Boolean.valueOf(value) : defaultValue; } protected Integer integerValueOf(String value, Integer defaultValue) { return value != null ? Integer.valueOf(value) : defaultValue; } protected Set stringSetValueOf(String value, String defaultValue) { value = value != null ? value : defaultValue; return new HashSet(Arrays.asList(value.split(","))); } //获取别名对应的JdbcType protected JdbcType resolveJdbcType(String alias) { if(alias == null) return null; return JdbcType.valueOf(alias); IllegalArgumentException e; e; throw new BuilderException((new StringBuilder()).append("Error resolving JdbcType. Cause: ").append(e).toString(), e); } }
从上的分析可以看出Cache的节点的解析,实际上是,获取cache节点的type对应的Class,
cache节点的eviction对应的缓存算法Class,以及刷新间隔,读写属性,构造CacheBuilder
,并添加的configuration的二级缓存StrictMap<nameSpace,CacheBuilder>
//CacheBuilder
public class CacheBuilder { private String id;//缓存命名空间 private Class implementation;//缓存实现类 private List decorators;//缓存算法,缓存解决集合 private Integer size; private Long clearInterval;//刷新间隔 private boolean readWrite;//读写属性 private Properties properties; public CacheBuilder(String id) { this.id = id; decorators = new ArrayList(); } //设置缓存属性 private void setCacheProperties(Cache cache) { if(properties != null) { MetaObject metaCache = SystemMetaObject.forObject(cache); Iterator i$ = properties.entrySet().iterator(); do { if(!i$.hasNext()) break; java.util.Map.Entry entry = (java.util.Map.Entry)i$.next(); String name = (String)entry.getKey(); String value = (String)entry.getValue(); if(metaCache.hasSetter(name)) { Class type = metaCache.getSetterType(name); if(java/lang/String == type) metaCache.setValue(name, value); else if(Integer.TYPE == type || java/lang/Integer == type) metaCache.setValue(name, Integer.valueOf(value)); else if(Long.TYPE == type || java/lang/Long == type) metaCache.setValue(name, Long.valueOf(value)); else if(Short.TYPE == type || java/lang/Short == type) metaCache.setValue(name, Short.valueOf(value)); else if(Byte.TYPE == type || java/lang/Byte == type) metaCache.setValue(name, Byte.valueOf(value)); else if(Float.TYPE == type || java/lang/Float == type) metaCache.setValue(name, Float.valueOf(value)); else if(Boolean.TYPE == type || java/lang/Boolean == type) metaCache.setValue(name, Boolean.valueOf(value)); else if(Double.TYPE == type || java/lang/Double == type) metaCache.setValue(name, Double.valueOf(value)); else throw new CacheException((new StringBuilder()).append("Unsupported property type for cache: '").append(name).append("' of type ").append(type).toString()); } } while(true); } } }
//MetaObject,设置Class实例属性
public class MetaObject { private Object originalObject;//原始Obeject private ObjectWrapper objectWrapper;//包装后的Object private ObjectFactory objectFactory; private ObjectWrapperFactory objectWrapperFactory; private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) { originalObject = object; this.objectFactory = objectFactory; this.objectWrapperFactory = objectWrapperFactory; if(object instanceof ObjectWrapper) objectWrapper = (ObjectWrapper)object; else //如果对应objectWrapperFactory中存在,则返回object if(objectWrapperFactory.hasWrapperFor(object)) objectWrapper = objectWrapperFactory.getWrapperFor(this, object); else if(object instanceof Map) //Map objectWrapper = new MapWrapper(this, (Map)object); else if(object instanceof Collection) //List objectWrapper = new CollectionWrapper(this, (Collection)object); else //bean objectWrapper = new BeanWrapper(this, object); } //构造MetaObject public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) { if(object == null) return SystemMetaObject.NULL_META_OBJECT; else return new MetaObject(object, objectFactory, objectWrapperFactory); } public String findProperty(String propName, boolean useCamelCaseMapping) { return objectWrapper.findProperty(propName, useCamelCaseMapping); } public String[] getGetterNames() { return objectWrapper.getGetterNames(); } public String[] getSetterNames() { return objectWrapper.getSetterNames(); } }
这个我们在后面单讲
//配置parameterMap
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
parameterMap配置实例
<!-- <parameterMap id="course_param" type="java.util.Map"> <parameter property="subjectCode" javaType="java.lang.String"/> <parameter property="courseNumber" javaType="java.lang.String"/> <parameter property="termCode" javaType="java.lang.String"/> <parameter property="pidm" javaType="int"/> </parameterMap> -->
private void parameterMapElement(List list) throws Exception { String id; //parameterMap的id Class parameterClass;//parameterMap的type List parameterMappings; //遍历所有的,parameterMap,并解析构造parameterMappings,在添加到configuration的ParameterMap中 for(Iterator i$ = list.iterator(); i$.hasNext(); builderAssistant.addParameterMap(id, parameterClass, parameterMappings)) { XNode parameterMapNode = (XNode)i$.next(); //获取parameterMap的id,type id = parameterMapNode.getStringAttribute("id"); String type = parameterMapNode.getStringAttribute("type"); parameterClass = resolveClass(type); //获取parameterMap的所有parameter子节点 List parameterNodes = parameterMapNode.evalNodes("parameter"); //parameterMappings,ArrayList<ParameterMapping> parameterMappings = new ArrayList(); org.apache.ibatis.mapping.ParameterMapping parameterMapping; //遍历所有的parameter节点,根据parameter节点属性构建ParameterMapping,并添加到parameterMappings for(Iterator i$ = parameterNodes.iterator(); i$.hasNext(); parameterMappings.add(parameterMapping)) { XNode parameterNode = (XNode)i$.next(); //获取parameter的property,javaType,jdbcType,resultMap,mode,typeHandler,numericScale属性 String property = parameterNode.getStringAttribute("property"); String javaType = parameterNode.getStringAttribute("javaType"); String jdbcType = parameterNode.getStringAttribute("jdbcType"); String resultMap = parameterNode.getStringAttribute("resultMap"); String mode = parameterNode.getStringAttribute("mode"); String typeHandler = parameterNode.getStringAttribute("typeHandler"); Integer numericScale = parameterNode.getIntAttribute("numericScale", null); // 获取mode的ParameterMode类型 org.apache.ibatis.mapping.ParameterMode modeEnum = resolveParameterMode(mode); // 获取javaTypeClass类型 Class javaTypeClass = resolveClass(javaType); // 获取jdbcType类型 JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType); // 获取typeHandler类型 Class typeHandlerClass = resolveClass(typeHandler); //构建ParameterMapping parameterMapping = builderAssistant.buildParameterMapping(parameterClass, property, javaTypeClass, jdbcTypeEnum, resultMap, modeEnum, typeHandlerClass, numericScale); } } }
//MapperBuilderAssistant
public class MapperBuilderAssistant extends BaseBuilder { private String currentNamespace; private String resource; private Cache currentCache; private boolean unresolvedCacheRef; //ParameterMap添加到configuration中 public ParameterMap addParameterMap(String id, Class parameterClass, List parameterMappings) { //获取全局唯一的命名空间 id = applyCurrentNamespace(id, false); org.apache.ibatis.mapping.ParameterMap.Builder parameterMapBuilder = new org.apache.ibatis.mapping.ParameterMap.Builder(configuration, id, parameterClass, parameterMappings); ParameterMap parameterMap = parameterMapBuilder.build(); //ParameterMap添加到configuration中 configuration.addParameterMap(parameterMap); return parameterMap; } //ParameterMapping构建 public ParameterMapping buildParameterMapping(Class parameterType, String property, Class javaType, JdbcType jdbcType, String resultMap, ParameterMode parameterMode, Class typeHandler, Integer numericScale) { resultMap = applyCurrentNamespace(resultMap, true); Class javaTypeClass = resolveParameterJavaType(parameterType, property, javaType, jdbcType); TypeHandler typeHandlerInstance = resolveTypeHandler(javaTypeClass, typeHandler); org.apache.ibatis.mapping.ParameterMapping.Builder builder = new org.apache.ibatis.mapping.ParameterMapping.Builder(configuration, property, javaTypeClass); builder.jdbcType(jdbcType); builder.resultMapId(resultMap); builder.mode(parameterMode); builder.numericScale(numericScale); builder.typeHandler(typeHandlerInstance); return builder.build(); } }
//configuration
//ParameterMap的映射关系到configuration的parameterMaps中
//parameterMaps = new StrictMap("Parameter Maps collection");
//Map<nameSpace,ParameterMap>
public void addParameterMap(ParameterMap pm) { parameterMaps.put(pm.getId(), pm); }
//ParameterMapping,ParameterMap的参数映射描述
public class ParameterMapping { private Configuration configuration; private String property; private ParameterMode mode; private Class javaType; private JdbcType jdbcType; private Integer numericScale; private TypeHandler typeHandler; private String resultMapId; private String jdbcTypeName; private String expression; public static class Builder { public Builder mode(ParameterMode mode) { parameterMapping.mode = mode; return this; } public Builder javaType(Class javaType) { parameterMapping.javaType = javaType; return this; } public Builder jdbcType(JdbcType jdbcType) { parameterMapping.jdbcType = jdbcType; return this; } public Builder numericScale(Integer numericScale) { parameterMapping.numericScale = numericScale; return this; } public Builder resultMapId(String resultMapId) { parameterMapping.resultMapId = resultMapId; return this; } public Builder typeHandler(TypeHandler typeHandler) { parameterMapping.typeHandler = typeHandler; return this; } public Builder jdbcTypeName(String jdbcTypeName) { parameterMapping.jdbcTypeName = jdbcTypeName; return this; } public ParameterMapping build() { resolveTypeHandler(); return parameterMapping; } private void resolveTypeHandler() { if(parameterMapping.typeHandler == null && parameterMapping.javaType != null) { Configuration configuration = parameterMapping.configuration; //从configuration的typeHandlerRegistry获取TypeHandler TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); parameterMapping.typeHandler = typeHandlerRegistry.getTypeHandler(parameterMapping.javaType, parameterMapping.jdbcType); } } private ParameterMapping parameterMapping; public Builder(Configuration configuration, String property, TypeHandler typeHandler) { parameterMapping = new ParameterMapping(); parameterMapping.configuration = configuration; parameterMapping.property = property; parameterMapping.typeHandler = typeHandler; parameterMapping.mode = ParameterMode.IN; } public Builder(Configuration configuration, String property, Class javaType) { parameterMapping = new ParameterMapping(); parameterMapping.configuration = configuration; parameterMapping.property = property; parameterMapping.javaType = javaType; parameterMapping.mode = ParameterMode.IN; } } }
//ParameterMode
public final class ParameterMode extends Enum { public static ParameterMode[] values() { return (ParameterMode[])$VALUES.clone(); } public static ParameterMode valueOf(String name) { return (ParameterMode)Enum.valueOf(org/apache/ibatis/mapping/ParameterMode, name); } private ParameterMode(String s, int i) { super(s, i); } public static final ParameterMode IN; public static final ParameterMode OUT; public static final ParameterMode INOUT; private static final ParameterMode $VALUES[]; static { IN = new ParameterMode("IN", 0); OUT = new ParameterMode("OUT", 1); INOUT = new ParameterMode("INOUT", 2); $VALUES = (new ParameterMode[] { IN, OUT, INOUT }); } }
//ParameterMap
public class ParameterMap { private String id; private Class type; private List parameterMappings; public static class Builder { public Class type() { return parameterMap.type; } public ParameterMap build() { parameterMap.parameterMappings = Collections.unmodifiableList(parameterMap.parameterMappings); return parameterMap; } private ParameterMap parameterMap; public Builder(Configuration configuration, String id, Class type, List parameterMappings) { parameterMap = new ParameterMap(); parameterMap.id = id; parameterMap.type = type; parameterMap.parameterMappings = parameterMappings; } } }
//从configuration中移除未完成的ChacheRefs
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) { } } }
从上的分析可以看出ParameterMap的解析实际是解析ParameterMap的id,type属性和
parameter子节点;然后解析parameter的property,javaType,jdbcType,typeHalder,
resultMap的属性根据这些属性构建parameterMapping,并添加的parameterMappings(ArrayList<ParameterMapping>)集合中;然后再根据id,type属性和parameterMappings,构造ParameterMap,并添加到configuration的parameterMaps中
。
总结:
解析Mapper对应的xml文件,实际上是解析xml的mapper Xnode,具体到namespace属性,及cache,cache-ref,parameterMap,篇幅有限这一篇我们讲到namespace属性,及cache,cache-ref,parameterMap,这三部分的解析,我们都有小节,实际上就是将这些添加configuration的相应的cache,parameterMap的StrictMap中。
各小节的总结:
namespace:
从上面的方法可以看出,命名空间实际上是配置Mapper对应的MapperBuilderAssistantcurrentNamespace属性;
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,sql,及select|insert|update|delete子节点
//XMLMapperEntityResolver
public class XMLMapperEntityResolver implements EntityResolver { public XMLMapperEntityResolver() { } public InputSource resolveEntity(String publicId, String systemId) throws SAXException { if(publicId != null) publicId = publicId.toUpperCase(Locale.ENGLISH); if(systemId != null) systemId = systemId.toUpperCase(Locale.ENGLISH); InputSource source = null; try { String path = (String)doctypeMap.get(publicId); source = getInputSource(path, source); if(source == null) { path = (String)doctypeMap.get(systemId); source = getInputSource(path, source); } } catch(Exception e) { throw new SAXException(e.toString()); } return source; } private InputSource getInputSource(String path, InputSource source) { if(path != null) try { java.io.InputStream in = Resources.getResourceAsStream(path); source = new InputSource(in); } catch(IOException e) { } return source; } private static final Map doctypeMap; private static final String IBATIS_CONFIG_DOCTYPE; private static final String IBATIS_CONFIG_URL; private static final String IBATIS_MAPPER_DOCTYPE; private static final String IBATIS_MAPPER_URL; private static final String MYBATIS_CONFIG_DOCTYPE; private static final String MYBATIS_CONFIG_URL; private static final String MYBATIS_MAPPER_DOCTYPE; private static final String MYBATIS_MAPPER_URL; private static final String IBATIS_CONFIG_DTD = "org/apache/ibatis/builder/xml/mybatis-3-config.dtd"; private static final String IBATIS_MAPPER_DTD = "org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd"; static { doctypeMap = new HashMap(); IBATIS_CONFIG_DOCTYPE = "-//ibatis.apache.org//DTD Config 3.0//EN".toUpperCase(Locale.ENGLISH); IBATIS_CONFIG_URL = "http://ibatis.apache.org/dtd/ibatis-3-config.dtd".toUpperCase(Locale.ENGLISH); IBATIS_MAPPER_DOCTYPE = "-//ibatis.apache.org//DTD Mapper 3.0//EN".toUpperCase(Locale.ENGLISH); IBATIS_MAPPER_URL = "http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd".toUpperCase(Locale.ENGLISH); MYBATIS_CONFIG_DOCTYPE = "-//mybatis.org//DTD Config 3.0//EN".toUpperCase(Locale.ENGLISH); MYBATIS_CONFIG_URL = "http://mybatis.org/dtd/mybatis-3-config.dtd".toUpperCase(Locale.ENGLISH); MYBATIS_MAPPER_DOCTYPE = "-//mybatis.org//DTD Mapper 3.0//EN".toUpperCase(Locale.ENGLISH); MYBATIS_MAPPER_URL = "http://mybatis.org/dtd/mybatis-3-mapper.dtd".toUpperCase(Locale.ENGLISH); doctypeMap.put(IBATIS_CONFIG_URL, "org/apache/ibatis/builder/xml/mybatis-3-config.dtd"); doctypeMap.put(IBATIS_CONFIG_DOCTYPE, "org/apache/ibatis/builder/xml/mybatis-3-config.dtd"); doctypeMap.put(IBATIS_MAPPER_URL, "org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd"); doctypeMap.put(IBATIS_MAPPER_DOCTYPE, "org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd"); doctypeMap.put(MYBATIS_CONFIG_URL, "org/apache/ibatis/builder/xml/mybatis-3-config.dtd"); doctypeMap.put(MYBATIS_CONFIG_DOCTYPE, "org/apache/ibatis/builder/xml/mybatis-3-config.dtd"); doctypeMap.put(MYBATIS_MAPPER_URL, "org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd"); doctypeMap.put(MYBATIS_MAPPER_DOCTYPE, "org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd"); } }
上一篇: 全球手机盛会MWC2020新措施:禁止湖北旅客参加
下一篇: “千古第一仁君”宋仁宗,为何传位侄子?