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文件,并解析
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");
}
}