java解析mybaties.xml_mybatis源码分析之spring加载mapper.xml文件原理解析

本文深入分析mybatis中mapper.xml文件的加载方式,包括基于接口类路径、包路径、独立资源目录以及Spring配置的加载。在系统启动时,mapper配置文件会被合并到SqlSessionFactory。通过跟踪源码,解析过程涉及XMLMapperBuilder构造、配置元素解析、MappedStatement生成等关键步骤。理解这一过程对于优化mybatis配置和解决相关问题至关重要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先我们来看看mapper.xml文件的加载方式

第一种:基于mapper接口类具体路径配置

4b81e71a0a14d81066f96a9ebfb25d25.png

这种情况下,如果是非注解模式的话xml配置文件必须和这个类在同一级目录,且与Mapper类同名。项目结构类似

9b3b6fd74c94fa545914e93cea65e220.png

第二种:基于mapper类所在包的package路径配置

6d2bb9395ee02a69e1df393de53b47dd.png

其实这算是第一种的一个变种。一个配置mapper类,每次新加删除比较麻烦,直接扫描mapper类所在包。项目结构类似

62a60e40e6a362ce2463c277e7c1f8a1.png

第三种:把 Mapper 的xml配置文件单独放置到 resources 中

ef0ccbc0da4fefa54732a9d87ed9712f.png

和Mapper 类分开了,mapper接口位置还保持不动

01f44eaa3a1e9ff88c71a32e3594eb51.png

但是mapper.xml被移动到了resources目录

55a8d41b06eaf789d63a868b1cc5480b.png

第四种:使用spring配置加载mapper配置

bf98f8f6c844d8faed5f20a3e178a1c7.png

5760f575a240d626dbfdaf83390d551c.png

可以看到,是往sqlsessionfactory中注入一系列的属性值。

通过上面的四种配置方式,我们可以看到,mybatis有个默认潜规则:mapper接口类的名字和mapper.xml的名字是一致的。

基于上面的四种配置,可以引申出很多其他形式的配置,比如使用注解,基于实现原理再实现一遍,你就可开源xxx-mybatis-boot-start.jar类。小编们就是基于第四种实现原理,实现类一套,源码如下:

246a9f85548ecdfba78e69d748fde2de.png

其中res1 和res2使用一个即可。由于项目架构的性质,我们使用了两个(当然还可以更多,因为mapperlocation是数组)。

铺垫做完了,我们开始今天的主题《mybatis源码分析之mapper.xml文件加载原理解析》

分析源码,关键是找对入口。首先我们来看下setMapperLocations方法的作用(resource对象传入的已经是根据正则表达式匹配到的各个xml文件了)

b024b193bd45d2910aefdc09e0997f5e.png

“Set locations of MyBatis mapper files that are going to be merged into the {@code SqlSessionFactory}configuration at runtime.”。大概意思是讲:在系统启动时,这些mapper配置文件会被合并初始化到SqlSessionFactory。接下来我们来看下SqlSessionFactory初始化做了些什么。

本文代码的切入点是bean.getObject()。一路跟踪(bean.getObject()->afterPropertiesSet()->buildSqlSessionFactory()),并会发现,真正做事的是buildSqlSessionFactory(),其作用就是创建一个SqlSessionFactory实例并返回。

该方法源码比较长,不再贴源码,只解释下里面关键名词

configuration 、configLocation: mybatis配置文件,两者只会二选一加载,例如上面示例中的mybatis-config.xml。

objectFactory mybatis对象工厂(没用过)

objectWrapperFactory mybatis对象包装类工厂(没用过)

vfsmybatis虚拟文件系统,在应用服务内,提供一个非常简单的方式访问资源(没用过)

typeAliases 类型别名

typeHandlers 类型处理器

plugins 插件类(后续会讲)

typeHandlersPackage 类型处理器包路径

databaseIdProvider(官方描述MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。 MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的所有语句。 如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃)

mapperLocations mapper文件地址

56638231d69f32eb63441f195b3d8d1c.png

解析一个个mapper.xml文件,放入config,然后返回。下面看看XMLMapperBuilder是怎么解析的

第一步:new XMLMapperBuilder构造类,把xml文件解析成document。xml解析方式

第二步:xmlMapperBuilder.parse()。分析xml中的每个node,转化为对象。下面着重介绍这步

0373209fa6e0790b8bf3cb9c9cdb1855.png

configurationElement方法负责解析mapper节点下的各个子节点,并放入configuration中。回想一下mapper.xml的结构。

5abd104ed69cab2504ba824d09f2962d.png

4673dde3756e48a0cea2eda49c5b7f23.png

我们重点介绍下buildStatementFromContext(context.evalNodes(“select|insert|update|delete”))方法,该方法是解析增删改查语句生成MappedStatement,并放入configuration的mappedStatements中,解析失败的放入incompleteStatements失败列表。 注意mappedStatements是一个map,value为MappedStatement,key为什么形式呢。举个例子:如果你的接口类(之前的namespace)是com.org.userMapper,节点id为selectOne的话,该map的id为com.org.userMapper.selectOne。这样保证了不同接口类,可以使用相同名字

至此,mapper.xml的解析完成,我们在看看收尾工作是怎么做的

f3085bcd8c08bbf96dee0742ab777172.png

解析失败的记录会死循环处理,那么总的有地方触发处理这处理失败的语句。触发方法如下

63f34575c0ed7d778912f2a60075537d.png

该方法注释写到,当所有的mapper.xml文件加载完成,推荐只调用一次该方法,处理这些之前失败的记录。

于是查看该方法的调用栈得到

ef3b06a4fe4c9104499bdc2cf34218ef.png

系统启动完成后,会通过event机制调用一次

作者也玩公众号,欢迎关注《JAVA之庖丁解牛》

来源:[]()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值