欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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