Mybatis系列(九)mappers的四种配置方式及源码解析


上篇文章 Mybatis系列(八)databaseIdProvider及plugin简单介绍,我们对mybatis的数据库厂商标识和插件有了简单的认识,这一节我们来看mybatis配置文件最重要的一个节点mappers(映射器)。

一、mappers的配置——引入映射器的四种方法

1.使用相对于类路径的资源,通过resource引入映射器

    <mappers>
        <mapper resource="com/sean/mapper/UserMapper.xml"/>
    </mappers>

2.用包名,通过package引入映射器

    <mappers>
        <package name ="com.sean.mapper"/>
    </mappers>

3.用类的全限定名注册,通过class引入映射器

    <mappers>
        <mapper class="com.sean.mapper.UserMapper"/>
    </mappers>

4.使用完全限定资源定位符(URL)

    <mappers>
        <mapper url="file:///git2/mybatisDemo/src/main/resources/com/sean/mapper/UserMapper.xml"/>
    </mappers>

以上四种引入注册器的方式大家应该都清楚,平时开发中常用的也是通过resource引入注册器,但是笔者mybatisDemo项目通过package,class引入却一直报错。如果有遇到和笔者一样问题的,请往下看
报错如下:
在这里插入图片描述
没有找到有效的绑定。

使用这种方式必须保证 接口与mapper文件同名(不区分大小写)
,我这里贴一下我之前的项目结构在这里插入图片描述
可以看到配置文件的xml文件路径并没有和mapper接口对应,所以我测试的一会一直绑定不到mapper映射文件找不到指定的方法,于是我改成了这样的项目结构
在这里插入图片描述
再通过<package name ="com.sean.mapper"/>
就可以完成mapper的注入了。如何配置掌握了,那我们就来看mybatis是如何解析mappers节点的。

二、mappers源码解析

还是从xml解析mappers节点看起,XMLConfigBuilder类下的this.mapperElement(root.evalNode("mappers"));

    private void mapperElement(XNode parent) throws Exception {
        if (parent != null) {
            Iterator i$ = parent.getChildren().iterator();

            while(true) {
                while(i$.hasNext()) {
                    XNode child = (XNode)i$.next();
                    String resource;
                    //如果mappers节点的子节点是package, 那么就扫描package下的那么属性, 注入进configuration
                    if ("package".equals(child.getName())) {
                        resource = child.getStringAttribute("name");
                        this.configuration.addMappers(resource);
                    } else {
                    	//解析resource, url, class属性值 
                        resource = child.getStringAttribute("resource");
                        String url = child.getStringAttribute("url");
                        String mapperClass = child.getStringAttribute("class");
                        XMLMapperBuilder mapperParser;
                        InputStream inputStream;
                        //mappers节点只能指定resource, url, class中的一个,不能指定多个
                        if (resource != null && url == null && mapperClass == null) {
                            ErrorContext.instance().resource(resource);
                            inputStream = Resources.getResourceAsStream(resource);
                            mapperParser = new XMLMapperBuilder(inputStream, this.configuration, resource, this.configuration.getSqlFragments());
                            mapperParser.parse();
                        } else if (resource == null && url != null && mapperClass == null) {
                            ErrorContext.instance().resource(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<?> mapperInterface = Resources.classForName(mapperClass);
                            this.configuration.addMapper(mapperInterface);
                        }
                    }
                }

                return;
            }
        }
    }

查看源码,无论配置是哪种注入方式,最终的处理类都是XMLMapperBuilder 解析器的parse方法

    public void parse() {
    	//判断configuration对象是否已经加载对应的mapper.xml文件,避免重复加载
        if (!this.configuration.isResourceLoaded(this.resource)) {
        	//解析mapper.xml文件
            this.configurationElement(this.parser.evalNode("/mapper"));
            //加载mapper.xml文件,其实添加到Set集合
            this.configuration.addLoadedResource(this.resource);
            //绑定namespace与mapper.xml关系
            this.bindMapperForNamespace();
        }

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

至此,整个mybatis配置文件中的mappers节点与具体mapper.xmlmapper映射文件中指定的namespace绑定完成。后续便是mapper映射文件是如何解析我们写的SQL(select,insert,update,delete)以及如何指定参数类型和查询结果返回类型的,我们下节继续来看吧。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值