后端技术:Mybatis是如何解析配置文件的?
关注“Java后端技术全栈”
回复“面试”获取全套面试资料
在以前文章中,我们把Mybatis源码阅读的整个流程梳理了一遍。今天,我们来详细聊聊,Mybatis是如何解析配置文件的。
这是今天分析的流程图:
还是从案例开始。
demo案例
public static void main(String[] args) {String resource = "mybatis-config.xml";InputStream inputStream = null;SqlSession sqlSession = null;try {inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);sqlSession = sqlSessionFactory.openSession();UserMapper userMapper = sqlSession.getMapper(UserMapper.class);System.out.println(userMapper.selectById(1));} catch (Exception e) {e.printStackTrace();} finally {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}sqlSession.close();}}
见证奇迹
从SqlSessionFactoryBuilder
开始。
SqlSessionFactoryBuilder类
org.apache.ibatis.session.SqlSessionFactoryBuilder
该类里全是build方法各种重载。
//这个方法啥也没干
public SqlSessionFactory build(InputStream inputStream) {return build(inputStream, null, null);}
最终来到另外一个build方法里:
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {try {//创建一个XMLConfigBuilder对象 XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);return build(parser.parse());} catch (Exception e) {throw ExceptionFactory.wrapException("Error building SqlSession.", e);} finally {ErrorContext.instance().reset();try {inputStream.close();} catch (IOException e) {// Intentionally ignore. Prefer previous error.}}}
XMLConfigBuilder类
该类的构造方法重载:
首先进入:
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {super(new Configuration());ErrorContext.instance().resource("SQL Mapper Configuration");this.configuration.setVariables(props);this.parsed = false;this.environment = environment;this.parser = parser;
}
build(parser.parse());中的parser.parse();
mybatis-config.xml在哪里解析的呢?
请看下面这个方法:
//该方法返回一个Configuration对象
public Configuration parse() {if (parsed) {throw new BuilderException("Each XMLConfigBuilder can only be used once.");}parsed = true;//关键点parseConfiguration(parser.evalNode("/configuration"));return configuration;
}
parseConfiguration(parser.evalNode("/configuration"));
终于看到开始解析配置文件了:
进入方法parseConfiguration。
private void parseConfiguration(XNode root) {try {//issue #117 read properties firstpropertiesElement(root.evalNode("properties"));Properties settings = settingsAsProperties(root.evalNode("settings"));loadCustomVfs(settings);loadCustomLogImpl(settings);typeAliasesElement(root.evalNode("typeAliases"));pluginElement(root.evalNode("plugins"));objectFactoryElement(root.evalNode("objectFactory"));objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));reflectorFactoryElement(root.evalNode("reflectorFactory"));settingsElement(settings);// read it after objectFactory and objectWrapperFactory issue #631environmentsElement(root.evalNode("environments"));databaseIdProviderElement(root.evalNode("databaseIdProvider"));typeHandlerElement(root.evalNode("typeHandlers"));mapperElement(root.evalNode("mappers"));} catch (Exception e) {throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);}}
这里就是把mybatis-config.xml内容解析,然后设置到Configuration对象中。
那么我们定义的Mapper.xml是在哪里解析的呢?
我们的Mapper.xml在mybatis-config.xml中的配置是这样的:
<mapper>
使用方式有以下四种:
//1使用类路径
<mappers><mapper resource="org/mybatis/builder/AuthorMapper.xml"/><mapper resource="org/mybatis/builder/BlogMapper.xml"/><mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
//2使用绝对url路径
<mappers><mapper url="file:///var/mappers/AuthorMapper.xml"/><mapper url="file:///var/mappers/BlogMapper.xml"/><mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
//3使用java类名
<mappers><mapper class="org.mybatis.builder.AuthorMapper"/><mapper class="org.mybatis.builder.BlogMapper"/><mapper class="org.mybatis.builder.PostMapper"/>
</mappers>//4自动扫描包下所有映射器
<mappers><package name="org.mybatis.builder"/>
</mappers>
继续源码分析,我们在上面mybatis-config.xml解析中可以看到:
我们不妨进入这个方法看看:
private void mapperElement(XNode parent) throws Exception {if (parent != null) {for (XNode child : parent.getChildren()) {//自动扫描包下所有映射器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");//使用java类名if (resource != null && url == null && mapperClass == null) {ErrorContext.instance().resource(resource);//根据文件存放目录,读取XxxMapper.xmlInputStream inputStream = Resources.getResourceAsStream(resource);//映射器比较复杂,调用XMLMapperBuilder//注意在for循环里每个mapper都重新new一个XMLMapperBuilder,来解析XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());mapperParser.parse();//使用绝对url路径} else if (resource == null && url != null && mapperClass == null) {ErrorContext.instance().resource(url);InputStream inputStream = Resources.getUrlAsStream(url);//映射器比较复杂,调用XMLMapperBuilderXMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());mapperParser.parse();//使用类路径 } else if (resource == null && url == null && mapperClass != null) {Class<?> mapperInterface = Resources.classForName(mapperClass);//直接把这个映射加入配置configuration.addMapper(mapperInterface);} else {throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");}}}}}
这里刚刚和我们的上面说的<mapper>
使用的方式完全是一模一样的。
到这里,配置文件mybatis-config.xml和我们定义映射文件XxxMapper.xml就全部解析完成。
回到SqlSessionFactoryBuilder类
前面讲到了XMLConfigBuilder中的parse方法,并返回了一个Configuration对象。
build(parser.parse());
这个build方法就是传入一个Configuration对象,然后构建一个DefaultSqlSession对象。
public SqlSessionFactory build(Configuration config) {return new DefaultSqlSessionFactory(config);}
继续回到我们的demo代码中这一行代码里:
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
这一行代码就相当于:
SqlSessionFactory sqlSessionFactory = new new DefaultSqlSessionFactory();
到这里,我们的整个流程就搞定了。
IT技术分享社区
个人博客网站:https://programmerblog.xyz
文章推荐程序员效率:画流程图常用的工具程序员效率:整理常用的在线笔记软件远程办公:常用的远程协助软件,你都知道吗?51单片机程序下载、ISP及串口基础知识硬件:断路器、接触器、继电器基础知识
后端技术:Mybatis是如何解析配置文件的?相关推荐
- 后端技术:mybatis插件原理详解
关注"Java后端技术全栈" 回复"面试"获取全套面试资料 上次发文说到了如何集成分页插件MyBatis插件原理分析,看完感觉自己better了,今天我们接着来 ...
- MyBatis 源码分析 - 配置文件解析过程
文章目录 * 本文速览 1.简介 2.配置文件解析过程分析 2.1 配置文件解析入口 2.2 解析 properties 配置 2.3 解析 settings 配置 2.3.1 settings 节点 ...
- MyBatis事务管理解析:颠覆你心中对事务的理解
MyBatis事务管理解析:颠覆你心中对事务的理解! 1 .说到数据库事务,人们脑海里自然不自然的就会浮现出事务的四大特性.四大隔离级别.七大传播特性. 四大还好说,问题是七大传播特性是哪儿来的?是S ...
- MyBatis 事务管理解析和有关事务的几种特殊场景表现
点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:干掉 Navicat:这个 IDEA 的兄弟真香!个人原创100W+访问量博客:点击前往,查看更多 作者 | 祖 ...
- 后端:MyBatis 面试问题集锦
1.#{}和${}的区别是什么? 答:${}是Properties文件中的变量占位符,它可以用于标签属性值和sql内部,属于静态文本替换,比如${driver}会被静态替换为com.mysql.jdb ...
- Javaweb后端技术(下)02-Mybatis
目录 Mybatis 任务一:基本应用 一 框架简介 1.1 三层架构 1.2 框架 二 Mybatis简介 2.1 原始jdbc操作(查询数据) 2.2 原始jdbc操作的分析 2.3 Mybati ...
- 互联网后端技术栈大全!
大家好,我是宝哥! 使用Java后端技术的目的就是构建业务应用,为用户提供在线或者离线服务.因此,一个业务应用需要哪些技术.依赖哪些基础设施就决定了需要掌握的后端技术有哪些. 纵观整个互联网技术体系再 ...
- (架构)后端技术体系框架
1.后端技术体系框架 使用Java后端技术的目的就是构建业务应用,为用户提供在线或者离线服务.因此,一个业务应用需要哪些技术.依赖哪些基础设施就决定了需要掌握的后端技术有哪些.纵观整个互联网技术体系再 ...
- 对标阿里P8的MyBatis源码解析文档,面试/涨薪两不误,已献出膝盖
移动互联网的特点是大数据.高并发,对服务器往往要求分布式.高性能.高灵活等,而传统模式的Java数据库编程框架已经不再适用了. 在这样的背景下,一个Java的持久框架MyBatis走入了我们的世界,它 ...
最新文章
- .NetCore微服务Surging新手傻瓜式 入门教程 学习日志---结构简介(二)
- ssm三大框架工作原理_蒸发器最常见的三大工作原理
- 计算机控制系统a卷-答案,计算机控制系统2010-2011年试题A答案
- OSTaskDelReq()--请求删除任务函数
- 北邮 复习 软件工程_软件工程专业最厉害的32所大学,共分4个档次,第一档当之无愧!...
- 如何使用Java将字符串保存到文本文件?
- [机器学习] 机器学习中所说的“线性模型”是个什么东西?
- HDU 5834 Magic boy Bi Luo with his excited tree 树形DP
- [20150204]关于位图索引4.txt
- @scheduled注解配置时间_《SpringBoot整合redis、Scheduled/quartz定时任务》
- 示波器上1G/S 100MHZ的含义
- Win10编译和测试libModbus
- (超详细) eclispe如何连接SQL Server2019(通过JDBC驱动包连接)
- python判断是否回文_Python语言判断输入的是否是回文数的方法
- 光学设计ZEMAX——什么是MF、RMS均方根点半径
- Linux高可用之heartbeat
- web前端期末大作业 HTML+CSS+JavaScript web课程设计网页规划与设计 企业网站制作
- android登陆界面ui设计,UI设计师必备技能:常用字体规范
- OpenCV中如何保存Mat矩阵
- 直播系统程序,云豹直播提供优质直播程序及云服务
热门文章
- [你必须知道的css系列]第一回:丰富的利器终结篇:选择符的组合关系及选择符总结...
- 电脑控制苹果手机_必备神器,电脑控制手机
- python中加入绝对路径_理解Python中的绝对路径和相对路径
- 1. 观察者模式总结(C++)
- 33 -jQuery 属性操作,文档操作(未完成)
- spring boot 读取 application.properties 初始化bean
- 第五章 Response(JavaTM Servlet 规范3.1 )
- LeetCode OJ - Populating Next Right Pointers in Each Node II
- modprobe:FATAL: could not load /lib/modules/2.6.35-22-generic/modules.dep No such file or directory
- Go学习笔记—标准库Context