Mybatis源码解析(二)mapper-resultmap详解构造过程

勿以浮沙筑高台


config解析过程见文章:
Mybatis源码解析(一)newconfiguration构造过程
在上章的最后我们简单解析了一下mapper的过程。
1.转为流对象
2.创建一个mapper文件的解析对象
3.解析mapper配置文件
这张我们就详细解析一下构造过程。

//parent = mappers
 private void mapperElement(XNode parent) throws Exception {
 //判断有没有mappers元素
        if (parent != null) {
            Iterator var2 = parent.getChildren().iterator();
            while(true) {
                while(var2.hasNext()) {
                    XNode child = (XNode)var2.next();
                    String resource;
                    //判断是不是扫描形式的
                    if ("package".equals(child.getName())) {
                    	//是的话拿到name
                        resource = child.getStringAttribute("name");
                        //直接放入配置中心
                        //链接:AH-01
                        this.configuration.addMappers(resource);
                    } else {
                    	//如果不是
                    	//获取资源
                        resource = child.getStringAttribute("resource");
                        //url
                        String url = child.getStringAttribute("url");
                        //class
                        String mapperClass = child.getStringAttribute("class");
                        XMLMapperBuilder mapperParser;
                        InputStream inputStream;
                        //三者只能存在一个
                        if (resource != null && url == null && mapperClass == null) {
                        //如果是resource,resource指定的文件路径
                            ErrorContext.instance().resource(resource);
                            //把mapper配置文件转为一个输入流对象
                            inputStream = Resources.getResourceAsStream(resource);
                            //创建一个mapper文件的解析对象
                            //链接:AH-03
                            mapperParser = new XMLMapperBuilder(inputStream, this.configuration, resource, this.configuration.getSqlFragments());
                            //解析mapper配置文件
                            //链接:AH-04
                            mapperParser.parse();
                        } else if (resource == null && url != null && mapperClass == null) {
                        	//如果是url,url指定的文件路径
                            ErrorContext.instance().resource(url);
                            //将url指定的文件转为流
                            inputStream = Resources.getUrlAsStream(url);
                            mapperParser = new XMLMapperBuilder(inputStream, this.configuration, url, this.configuration.getSqlFragments());
                            mapperParser.parse();
                        } else {
                            if (resource != null || url != null || mapperClass == null) {
                                throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
                            }
							//如果是class将mapper对应的接口类型添加进configuration配置中心
                            Class<?> mapperInterface = Resources.classForName(mapperClass);
                            this.configuration.addMapper(mapperInterface);
                        }
                    }
                }
                return;
            }
        }
    }

AH-01:org.apache.ibatis.binding.MapperRegistry#addMappers(java.lang.String, java.lang.Class<?>)

  public void addMappers(String packageName, Class<?> superType) {
  		//通过反射工具类
        ResolverUtil<Class<?>> resolverUtil = new ResolverUtil();
        //解析当前name的实例
        //这个在上一章解析过,找到所有的.class不是接口,不是二进制文件的类
        resolverUtil.find(new IsA(superType), packageName);
        //拿到类对象
        Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
        Iterator var5 = mapperSet.iterator();

        while(var5.hasNext()) {
            Class<?> mapperClass = (Class)var5.next();
            //遍历后加入集合
            //链接:AH-02
            this.addMapper(mapperClass);
        	//return AH-01
        }
    }

AH-02:org.apache.ibatis.binding.MapperRegistry#addMapper

   public <T> void addMapper(Class<T> type) {
   		//判断是不是接口,因为我们这个类下的映射关系必须是接口类型
        if (type.isInterface()) {
        	//判断我们集合中是否已经存储过了
            if (this.hasMapper(type)) {
                throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
            }
            //完整度为false
            boolean loadCompleted = false;
            try {
            	//将类型和代理对象添加进集合
            	//MapperProxyFactory:创建这个接口实例的工厂代理对象
                this.knownMappers.put(type, new MapperProxyFactory(type));
                //获取mapper注解
                MapperAnnotationBuilder parser = new MapperAnnotationBuilder(this.config, type);
                //注解解析
                parser.parse();
                //解析完成
                loadCompleted = true;
                //return :AH-02
            } finally {
                if (!loadCompleted) {
                    this.knownMappers.remove(type);
                }
            }
        }
    }

AH-03:org.apache.ibatis.builder.xml.XMLMapperBuilder#XMLMapperBuilder(java.io.InputStream, org.apache.ibatis.session.Configuration, java.lang.String, java.util.Map<java.lang.String,org.apache.ibatis.parsing.XNode>)

 public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
//将流转为文档对象
this(new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver()), configuration, resource, sqlFragments);
    }

private XMLMapperBuilder(XPathParser parser, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
        //更新一下父类当中的配置文件
        super(configuration);
        //创建一个助理对象
        //传入
        //当前的config对象和resource,资源路径
        this.builderAssistant = new MapperBuilderAssistant(configuration, resource);
        //
        this.parser = parser;
        //
        this.sqlFragments = sqlFragments;
        //
        this.resource = resource;
    	//return AH-03
    }

AH-04:org.apache.ibatis.builder.xml.XMLMapperBuilder#parse

public void parse() {
		//判断当前资源是否被解析过
		//解析过会将资源名称放入属性
        if (!this.configuration.isResourceLoaded(this.resource)) {
            //开始解析mapper配置文件
            //先转换为一个XNode节点
            //链接:AH-05
            this.configurationElement(this.parser.evalNode("/mapper"));
            this.configuration.addLoadedResource(this.resource);
            this.bindMapperForNamespace();
        }

        this.parsePendingResultMaps();
        this.parsePendingCacheRefs();
        this.parsePendingStatements();
    }

AH-05:org.apache.ibatis.builder.xml.XMLMapperBuilder#configurationElement

private void configurationElement(XNode context) {
        try {
        	//解析namespce,
        	//<mapper namespace="com.mybatis.demo.mapper.UserMapper">	
            String namespace = context.getStringAttribute("namespace");
            //namespace!=null
            if (namespace != null && !namespace.equals("")) {
            	//通过构建助手,namesapce设置进去
                this.builderAssistant.setCurrentNamespace(namespace);
                //解析缓存引用标签
                //链接:AH-06
                this.cacheRefElement(context.evalNode("cache-ref"));
                //链接:AH-08
                //构建缓存对象
                this.cacheElement(context.evalNode("cache"));
                this.parameterMapElement(context.evalNodes("/mapper/parameterMap"));
				
				//resultmao
				//构建映射关系对象
				//链接:AH-12
                this.resultMapElements(context.evalNodes("/mapper/resultMap"));
                //映射SQL语句关系
                this.sqlElement(context.evalNodes("/mapper/sql"));
                this.buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
            } else {
                throw new BuilderException("Mapper's namespace cannot be empty");
            }
        } catch (Exception var3) {
            throw new BuilderException("Error parsing Mapper XML. The XML location is '" + this.resource + "'. Cause: " + var3, var3);
        }
    }

AH-06:org.apache.ibatis.builder.xml.XMLMapperBuilder#cacheRefElement

   private void cacheRefElement(XNode context) {
        if (context != null) {
            // <cache-ref namespace=""> <cache/>
            //判定指定的命名空间
            //保留当前命名空间和指定的命名空间
            this.configuration.addCacheRef(this.builderAssistant.getCurrentNamespace(), context.getStringAttribute("namespace"));
            
            CacheRefResolver cacheRefResolver = new CacheRefResolver(this.builderAssistant, context.getStringAttribute("namespace"));

            try {
            //开始对其进行解析
            //链接:AH-07
            //return AH-06
                cacheRefResolver.resolveCacheRef();
            } catch (IncompleteElementException var4) {
                this.configuration.addIncompleteCacheRef(cacheRefResolver);
            }
        }

    }

AH-07:``

public Cache resolveCacheRef() {
        return this.assistant.useCacheRef(this.cacheRefNamespace);
    }
   public Cache useCacheRef(String namespace) {
        if (namespace == null) {
            throw new BuilderException("cache-ref element requires a namespace attribute.");
        } else {
            try {
            	//不能解析
                this.unresolvedCacheRef = true;
                //通过名称到集合中拿
                Cache cache = this.configuration.getCache(namespace);
                if (cache == null) {
                //如果为空说明之前的构造没有成功
                    throw new IncompleteElementException("No cache for namespace '" + namespace + "' could be found.");
                } else {
                	//拿出缓存
                    this.currentCache = cache;
                    //可以解析
                    this.unresolvedCacheRef = false;
                    //return AH-07
                    return cache;
                }
            } catch (IllegalArgumentException var3) {
                throw new IncompleteElementException("No cache for namespace '" + namespace + "' could be found.", var3);
            }
        }
    }

AH-08:org.apache.ibatis.builder.xml.XMLMapperBuilder#cacheElement

  private void cacheElement(XNode context) {
        if (context != null) {
        	//拿到type属性,没有设置的话默认值为PERPETUAL
        	//之前的缓存集合里有特定的类型可以指定
        	//    <cache-ref namespace="">
			//		<cache type="LRU"/>
    		//	<cache/>
            String type = context.getStringAttribute("type", "PERPETUAL");
            //通过映射关系找到类型eg:LRU的对应的类型
            Class<? extends Cache> typeClass = this.typeAliasRegistry.resolveAlias(type);
            //寻找淘汰策略
            String eviction = context.getStringAttribute("eviction", "LRU");
            //找到类型 
            Class<? extends Cache> evictionClass = this.typeAliasRegistry.resolveAlias(eviction);
            //得到刷新的时间
            Long flushInterval = context.getLongAttribute("flushInterval");
            //设置的缓存大小
            Integer size = context.getIntAttribute("size");
            //是否分块读取
            boolean readWrite = !context.getBooleanAttribute("readOnly", false);
            //是否堵塞
            boolean blocking = context.getBooleanAttribute("blocking", false);
            //获取子属性集合
            Properties props = context.getChildrenAsProperties();
            //将生成的属性值,保存进构建助手对象中
            //AH-09
            this.builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);
            //return AH-08
        }
    }

AH-09:org.apache.ibatis.builder.MapperBuilderAssistant#useNewCache

public Cache useNewCache(Class<? extends Cache> typeClass, Class<? extends Cache> evictionClass, Long flushInterval, Integer size, boolean readWrite, boolean blocking, Properties props) {
		//链接:AH-09
        Cache cache = (new CacheBuilder(this.currentNamespace)).implementation((Class)this.valueOrDefault(typeClass, PerpetualCache.class)).addDecorator((Class)this.valueOrDefault(evictionClass, LruCache.class)).clearInterval(flushInterval).size(size).readWrite(readWrite).blocking(blocking).properties(props).build();
        //将缓存对象添加进config
        this.configuration.addCache(cache);
        //赋值
        this.currentCache = cache;
        //return AH-09
        return cache;
    }

AH-10:org.apache.ibatis.mapping.CacheBuilder#build

    public Cache build() {
        this.setDefaultImplementations();
        Cache cache = this.newBaseCacheInstance(this.implementation, this.id);
        //设置缓存的属性集合
        //链接:AH-10
        this.setCacheProperties((Cache)cache);
        //PerpetualCache.class这个类和当前缓存类型进行匹配
        if (PerpetualCache.class.equals(cache.getClass())) {
            Iterator var2 = this.decorators.iterator();
            while(var2.hasNext()) {
                Class<? extends Cache> decorator = (Class)var2.next();
                //反射生成一个装饰实例
                cache = this.newCacheDecoratorInstance(decorator, (Cache)cache);
                //设置入缓存
                this.setCacheProperties((Cache)cache);
            }
            cache = this.setStandardDecorators((Cache)cache);
            //判断是否是日志缓存派生的
        } else if (!LoggingCache.class.isAssignableFrom(cache.getClass())) {
            //如果不是,则创建一个日志缓存
            cache = new LoggingCache((Cache)cache);
        }
        //return AH-10
        return (Cache)cache;
    }

AH-11:org.apache.ibatis.mapping.CacheBuilder#setCacheProperties

private void setCacheProperties(Cache cache) {
        if (this.properties != null) {
        	//拿到元数据内部有各种获取属性设置反射的方法
            MetaObject metaCache = SystemMetaObject.forObject(cache);
            Iterator var3 = this.properties.entrySet().iterator();

            label76:
            while(true) {
                while(true) {
                    String name;
                    String value;
                    do {
                        if (!var3.hasNext()) {
                            break label76;
                        }
                        Entry<Object, Object> entry = (Entry)var3.next();
                        name = (String)entry.getKey();
                        value = (String)entry.getValue();
                    } while(!metaCache.hasSetter(name));

                    Class<?> type = metaCache.getSetterType(name);
                    //获取当前属性对应的类型
                    if (String.class == type) {
                    //setvalue的时候其实调用的就是反射区构建实例
                        metaCache.setValue(name, value);
                    } else if (Integer.TYPE != type && Integer.class != type) {
                        if (Long.TYPE != type && Long.class != type) {
                            if (Short.TYPE != type && Short.class != type) {
                                if (Byte.TYPE != type && Byte.class != type) {
                                    if (Float.TYPE != type && Float.class != type) {
                                        if (Boolean.TYPE != type && Boolean.class != type) {
                                            if (Double.TYPE != type && Double.class != type) {
                                                throw new CacheException("Unsupported property type for cache: '" + name + "' of type " + type);
                                            }

                                            metaCache.setValue(name, Double.valueOf(value));
                                        } else {
                                            metaCache.setValue(name, Boolean.valueOf(value));
                                        }
                                    } else {
                                        metaCache.setValue(name, Float.valueOf(value));
                                    }
                                } else {
                                    metaCache.setValue(name, Byte.valueOf(value));
                                }
                            } else {
                                metaCache.setValue(name, Short.valueOf(value));
                            }
                        } else {
                            metaCache.setValue(name, Long.valueOf(value));
                        }
                    } else {
                        metaCache.setValue(name, Integer.valueOf(value));
                    }
                }
            }
        }
        //判断你的缓存类是否是由InitializingObject接口派生的
         if (InitializingObject.class.isAssignableFrom(cache.getClass())) {
            try {
            //如果是这个派生的,调用initialize方法初始化属性值
                ((InitializingObject)cache).initialize();
            } catch (Exception var8) {
                throw new CacheException("Failed cache initialization for '" + cache.getId() + "' on '" + cache.getClass().getName() + "'", var8);
            }
        }
        //return AH-11
    }

AH-12:org.apache.ibatis.builder.xml.XMLMapperBuilder#resultMapElements

//会把resultmap下的所有节点返回回来
   private void resultMapElements(List<XNode> list) throws Exception {
        Iterator var2 = list.iterator();
		//遍历节点集合
        while(var2.hasNext()) {
            XNode resultMapNode = (XNode)var2.next();
            try {
            	//对resultmap的元素进行解读
            	//链接:AH-13
            	//return:AH-12
                this.resultMapElement(resultMapNode);
            } catch (IncompleteElementException var5) {
            }
        }
    }

AH-13:org.apache.ibatis.builder.xml.XMLMapperBuilder#resultMapElement(org.apache.ibatis.parsing.XNode, java.util.List<org.apache.ibatis.mapping.ResultMapping>, java.lang.Class<?>)

private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings, Class<?> enclosingType) throws Exception {
        ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier());
        //首先拿取主键配置的ID值,构建一个string返回
        String id = resultMapNode.getStringAttribute("id", resultMapNode.getValueBasedIdentifier());
        //获取type属性可能是oftype,resulttype,javatype
        String type = resultMapNode.getStringAttribute("type", 
        resultMapNode.getStringAttribute("ofType", resultMapNode.getStringAttribute("resultType", resultMapNode.getStringAttribute("javaType"))));
        //获取继承属性值
        String extend = resultMapNode.getStringAttribute("extends");
        //自动根据小驼峰命名方式匹配
        Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");
        //解读当前别名称对象的类类型
        Class<?> typeClass = this.resolveClass(type);
        if (typeClass == null) {
        	//如果等于空,则找继承类型
            typeClass = this.inheritEnclosingType(resultMapNode, enclosingType);
        }
		//鉴别器
        Discriminator discriminator = null;
        //每一行映射关系就是一个resultmapping对象,构建一个resultmapping对象集合
        List<ResultMapping> resultMappings = new ArrayList();
        //将映射关系添加进resultMappings
        resultMappings.addAll(additionalResultMappings);
        //获得所有的子节点
        List<XNode> resultChildren = resultMapNode.getChildren();
        Iterator var12 = resultChildren.iterator();
		//对所有的子节点进行遍历
        while(var12.hasNext()) {
            XNode resultChild = (XNode)var12.next();
            //如果是构造器就按构造进行解析
            if ("constructor".equals(resultChild.getName())) {
                this.processConstructorElement(resultChild, typeClass, resultMappings);  
                //如果是鉴别器就鉴别器进行解析
            } else if ("discriminator".equals(resultChild.getName())) {
                discriminator = this.processDiscriminatorElement(resultChild, typeClass, resultMappings);
            } else {
              //如果是主键就主键器进行解析
                List<ResultFlag> flags = new ArrayList();
                if ("id".equals(resultChild.getName())) {
                    flags.add(ResultFlag.ID);
                }
                //将当前的结果,类型,和主键表示添加进resultMappings,构建一个resultMappings对象出来
                resultMappings.add(this.buildResultMappingFromContext(resultChild, typeClass, flags));
            }
        }
        
        //将生成的resultMappings集合和属性信息包装一下为ResultMapResolver 类
        ResultMapResolver resultMapResolver = new ResultMapResolver(this.builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);

        try {
        //对继承resultmap的处理
        //链接:AH-14
        //return:AH-13
            return resultMapResolver.resolve();
        } catch (IncompleteElementException var15) {
            this.configuration.addIncompleteResultMap(resultMapResolver);
            throw var15;
        }
    }

AH-14:org.apache.ibatis.builder.MapperBuilderAssistant#addResultMap

  public ResultMap addResultMap(String id, Class<?> type, String extend, Discriminator discriminator, List<ResultMapping> resultMappings, Boolean autoMapping) {
		//获取命名空间
        id = this.applyCurrentNamespace(id, false);
        //获取继承关系
        extend = this.applyCurrentNamespace(extend, true);
        ResultMap resultMap;
        if (extend != null) {
        //如果id想到,则继承reusultmap
            if (!this.configuration.hasResultMap(extend)) {
                throw new IncompleteElementException("Could not find a parent resultmap with id '" + extend + "'");
            }
			//获取继承对象
            resultMap = this.configuration.getResultMap(extend);
            List<ResultMapping> extendedResultMappings = new ArrayList(resultMap.getResultMappings());
            extendedResultMappings.removeAll(resultMappings);
            boolean declaresConstructor = false;
            Iterator extendedResultMappingsIter = resultMappings.iterator();
			//进行整合
            while(extendedResultMappingsIter.hasNext()) {
                ResultMapping resultMapping = (ResultMapping)extendedResultMappingsIter.next();
                if (resultMapping.getFlags().contains(ResultFlag.CONSTRUCTOR)) {
                    declaresConstructor = true;
                    break;
                }
            }
			//构造器整理
            if (declaresConstructor) {
                extendedResultMappingsIter = extendedResultMappings.iterator();

                while(extendedResultMappingsIter.hasNext()) {
                    if (((ResultMapping)extendedResultMappingsIter.next()).getFlags().contains(ResultFlag.CONSTRUCTOR)) {
                        extendedResultMappingsIter.remove();
                    }
                }
            }
			//将整理好的信息放进集合中
            resultMappings.addAll(extendedResultMappings);
        }

        resultMap = (new org.apache.ibatis.mapping.ResultMap.Builder(this.configuration, id, type, resultMappings, autoMapping)).discriminator(discriminator).build();
        this.configuration.addResultMap(resultMap);
        //return AH-14
        return resultMap;
    }

总计:
1.AH-04:判断有没有mappers元素,创建一个xmlmapperbuiler对资源进行解析,将流转为文档对象。
2.解析文档对象,先接下namespace,和env的是否一致,一致则进行resultmap对象,获取所有子节点,根据子节点的名称选择不同的处理器进行处理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值