Mybatis初始化加载流程————Mapper接口注册

本篇博客是接着上一篇博客的《Mybatis初始化加载流程—-配置文件解析》,里面使用到的接口和配置文件是一样对的。这里的Mapper接口注册,也只是注册即将用来生成MapperProxy对象的MapperProxyFactory实例,在后面获取接口代理的时候会直接使用MapperProxyFactory的getObject方法,MapperProxyFactory类实现了FactoryBean<T>接口。
下面看一下如何在系统注册MapperProxyFactory相关信息的。

public void parse() {
        //判断当前mapper.xml文件是否已经被解析过
        if (!configuration.isResourceLoaded(resource)) {
            //在configurationElement完成mapper.xml中所有元素的解析,并将解析出来的相关属性全部保存在configuration中
            configurationElement(parser.evalNode("/mapper"));
            configuration.addLoadedResource(resource);
            //将mapper配置文件对应对的接口注册到configuration中。
            bindMapperForNamespace();
        }

        parsePendingResultMaps();
        parsePendingCacheRefs();
        parsePendingStatements();
    }

直接看注册信息的那一部分,也就是绑定Namespace的那一部分。

    private void bindMapperForNamespace() {
        String namespace = builderAssistant.getCurrentNamespace();
        if (namespace != null) {
            Class<?> boundType = null;
            try {
                //这里获取的boundType实际上就是java中定义的接口名
                boundType = Resources.classForName(namespace);
            } catch (ClassNotFoundException e) {
                //ignore, bound type is not required
            }
            if (boundType != null) {
                if (!configuration.hasMapper(boundType)) {
                    // Spring may not know the real resource name so we set a flag
                    // to prevent loading again this resource from the mapper interface
                    // look at MapperAnnotationBuilder#loadXmlResource
                    configuration.addLoadedResource("namespace:" + namespace);
                    //添加接口类型到Configuration中的MapperRegistery中
                    configuration.addMapper(boundType);
                }
            }
        }
    }

在Configuration对象中存在一个MapperRegistry对象,实际保存接口是mapperRegistry对象

    public <T> void addMapper(Class<T> type) {
        mapperRegistry.addMapper(type);
    }

在MapperRegistry对象中保存接口信息,并且保存用来生成接口代理的MapperProxyFactory的实体对象。

    //使用一个Mapper保存相关信息,用接口的类型作为key,根据接口类型创建一个MapperProxyFactory对象
    //这个对象很重要,在后面获取接口的代理对象就是通过这个对象获取的,MapperProxyFactory实现了FactoryBean接口
    public <T> void addMapper(Class<T> type) {
        if (type.isInterface()) {
            if (hasMapper(type)) {
                throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
            }
            boolean loadCompleted = false;
            try {
                //现在在knownMappers这个集合中已经存在一个以接口类名为key,value为MapperProxyFactory的对象了
                //其中将接口类型传入到MapperProxyFactory对象中
                knownMappers.put(type, new MapperProxyFactory<T>(type));
                // It's important that the type is added before the parser is run
                // otherwise the binding may automatically be attempted by the
                // mapper parser. If the type is already known, it won't try.
                MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
                parser.parse();
                loadCompleted = true;
            } finally {
                if (!loadCompleted) {
                    knownMappers.remove(type);
                }
            }
        }
    }

到目前为止,已经生成了MapperProxyFactory对象了,并且可以根据接口的名称获取MapperProxyFactory对象了。下一步需要知道系统是如何注册根据接口名生成的beanName为名字的BeanDefinition,并且如何确定beanName与具体的beanClass关系。实际上在测试代码中声明的接口为com.interfaces.CityMapper,所以beanName应该是为cityMapper,但是实际上beanClass为MapperFactoryBean<T>,下一篇博客将分析如何确定二者之间的关系的。

猜你喜欢

转载自blog.csdn.net/u011043551/article/details/80619319