`
Donald_Draper
  • 浏览: 981286 次
社区版块
存档分类
最新评论

Mybatis加载解析Mapper(xml)文件第一讲

阅读更多
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");
    }
}
0
2
分享到:
评论

相关推荐

    MyBatis基本了解

    创建MyBatis的第一个实例通常涉及以下步骤: 1. 创建数据库表。 2. 创建项目,导入MyBatis所需的jar包。 3. 编写实体类,比如User类。 4. 编写映射文件UserMapper.xml和UserMapper接口,声明需要的方法。 5. 配置...

    mybatis3.4.5完整jar包下载

    2. **MyBatis-SQLMapClient**:这部分提供了对XML配置文件的处理,用于读取和解析Mapper配置。 3. **MyBatis-Plus**(可选):这是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提高...

    手写mybatis

    1. 加载XML文件:使用Java的`javax.xml.parsers.DocumentBuilderFactory`创建一个DocumentBuilder,并通过它加载XML文件。 2. 解析XML:通过`DocumentBuilder`的parse()方法解析XML文档,得到一个Document对象。 3...

    MyBatis Generator代码自动生成

    1. **加载配置文件**:配置文件通常为XML格式,包含数据库连接信息、表名、生成的Java包路径等。 2. **解析数据库元数据**:获取表结构、字段信息等,这是生成代码的基础。 3. **生成Java代码**:基于解析出的数据库...

    2022.9.26-mybatis-源码.rar

    "01-Mybatis10-第一个mybatis程序"涵盖了Mybatis的基本使用步骤,包括配置Mybatis的主配置文件(mybatis-config.xml)、创建Mapper接口、编写Mapper XML文件以及实体类。在实际运行时,Mybatis会加载配置文件,根据...

    mybatis 入门文档

    创建 `SqlSessionFactory` 是 MyBatis 使用的第一步,它是线程安全的,可以在应用程序中被共享和复用。 - **读取配置文件**:可以通过 `InputStream` 或者 `Reader` 来读取 MyBatis 的配置文件。 - **构建 `...

    mybatis第二天课堂笔记

    - **where 子句**:自动添加 where 关键字,并处理第一个 where 后面的 and/or 问题。 - **foreach 循环**:循环遍历集合或数组。 - **SQL 片段**:重用 SQL 代码块。 #### 六、高级映射案例 - **一对一查询**:...

    spring-boot-starter-mybatis-spring-boot-1.3.0.zip

    4. Mapper配置:通过在Java类路径下的mybatis目录下放置Mapper XML文件,或者使用注解式Mapper,可以方便地定义SQL语句。 五、实战演练 1. 创建Spring Boot项目:首先创建一个基于Spring Boot的新项目,并在pom.xml...

    SpringBoot整合mybatis.docx

    为了自动化生成MyBatis的实体类、Mapper接口和XML映射文件,我们可以使用MyBatis Generator。在`generatorConfig.xml`配置文件中指定数据库连接信息、生成的目标包路径等。然后通过命令行或IDE插件运行Generator。...

    Xuefeng的Mybatis学习代码.rar

    3. **Mapper接口与XML配置**:解析Mapper接口和对应的XML配置文件,理解SQL语句如何在XML中编写,以及如何通过注解方式实现映射。 4. **基本 CRUD 操作**:展示如何使用MyBatis执行增删改查操作,包括动态SQL和结果...

    MyBatis 14道面试题和答案.docx

    MyBatis将SQL语句分离到mapper.xml文件中,使得SQL和Java代码解耦,方便修改。 - **参数传递**:JDBC传递参数繁琐,MyBatis通过动态SQL和参数映射简化这一过程,能够自动将Java对象转化为SQL语句的参数。 - **结果...

    尚硅谷 4月份MyBatis视频教程(国内首套:源码级讲授的MyBatis视频)最新更新

    根据提供的文件信息,本次将对MyBatis框架的相关知识点进行深入解析。MyBatis是一款优秀的持久层框架,它支持自定义SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集,通过...

    MyBatis第一天课堂笔记.docx

    MyBatis 是一个基于 Java 的持久层框架,它致力于简化 SQL 查询的处理,提供了灵活的 SQL 和 XML 或注解的映射方式,使得开发者能够专注于 SQL 本身,而无需关注 JDBC 的繁琐操作。MyBatis 从前身为 Apache 的 ...

    mybatis定时任务列表查询分页切割

    MyBatis作为一个轻量级的持久层框架,提供了强大的SQL映射和数据访问能力,但在处理大量数据时,一次性加载所有结果可能会导致内存溢出,因此分页查询显得尤为重要。本文将详细介绍如何在MyBatis中实现定时任务列表...

    mybatis 资料 帮助文档

    首先,"mybatis教案-day01-2.0.docx" 和 "mybatis教案-day01-2.0.pdf" 可能是针对 MyBatis 入门课程的第一天教学内容,可能包含了基本概念介绍、环境搭建、XML 配置文件解析、Mapper 接口定义以及动态 SQL 等内容。...

    MyBatis3用户指南

    #### 第一章 什么是MyBatis **MyBatis** 是一款非常流行的 SQL 映射框架,最初由 Clinton Begin 在 2002 年创建。随后,该框架被捐献给 Apache 基金会,并在此基础上成立了 iBatis 项目。到了 2010 年 5 月,项目的...

    Mybatis多对多关联映射源码

    - **XML映射文件配置**:在Mapper XML文件中,使用`&lt;association&gt;`和`&lt;collection&gt;`元素来定义多对多关系。`&lt;collection&gt;`元素用于表示一对多或多对多关系,而`&lt;association&gt;`则表示一对一或多对一关系。 - **注解...

    mybatis学习笔记

    - **第一步**:生成mapper配置文件。 - **第二步**:使用Java类生成mapper文件。 - **第三步**:拷贝生成的mapper文件到工程中指定的目录中。 - **Mapper.xml**:生成的映射文件。 - **Mapper.java**:生成的接口...

    ssm框架整合的第三个阶段:完成了springmvc框架的配置和spring框架的配置,配置mybatis环境,将spring、springmvc、mybati

    4. 整合MyBatis与Spring:使用Spring的SqlSessionFactoryBean加载MyBatis的配置,将Mapper接口与XML映射文件关联。 5. 测试:编写JUnit测试用例,确保SSM框架整合成功,各个组件能正常工作。 在实际开发中,我们...

    MyBatis简介.docx

    MyBatis 的动态 SQL 是通过 XML 映射文件中的特定标签实现的,如 trim、where、set、foreach、if、choose、when、otherwise、bind 等。这些标签能够帮助我们在运行时根据条件动态地拼接 SQL 语句,其执行原理是利用 ...

Global site tag (gtag.js) - Google Analytics