关注“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是如何解析配置文件的?相关推荐

  1. 后端技术:mybatis插件原理详解

    关注"Java后端技术全栈" 回复"面试"获取全套面试资料 上次发文说到了如何集成分页插件MyBatis插件原理分析,看完感觉自己better了,今天我们接着来 ...

  2. MyBatis 源码分析 - 配置文件解析过程

    文章目录 * 本文速览 1.简介 2.配置文件解析过程分析 2.1 配置文件解析入口 2.2 解析 properties 配置 2.3 解析 settings 配置 2.3.1 settings 节点 ...

  3. MyBatis事务管理解析:颠覆你心中对事务的理解

    MyBatis事务管理解析:颠覆你心中对事务的理解! 1 .说到数据库事务,人们脑海里自然不自然的就会浮现出事务的四大特性.四大隔离级别.七大传播特性. 四大还好说,问题是七大传播特性是哪儿来的?是S ...

  4. MyBatis 事务管理解析和有关事务的几种特殊场景表现

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:干掉 Navicat:这个 IDEA 的兄弟真香!个人原创100W+访问量博客:点击前往,查看更多 作者 | 祖 ...

  5. 后端:MyBatis 面试问题集锦

    1.#{}和${}的区别是什么? 答:${}是Properties文件中的变量占位符,它可以用于标签属性值和sql内部,属于静态文本替换,比如${driver}会被静态替换为com.mysql.jdb ...

  6. Javaweb后端技术(下)02-Mybatis

    目录 Mybatis 任务一:基本应用 一 框架简介 1.1 三层架构 1.2 框架 二 Mybatis简介 2.1 原始jdbc操作(查询数据) 2.2 原始jdbc操作的分析 2.3 Mybati ...

  7. 互联网后端技术栈大全!

    大家好,我是宝哥! 使用Java后端技术的目的就是构建业务应用,为用户提供在线或者离线服务.因此,一个业务应用需要哪些技术.依赖哪些基础设施就决定了需要掌握的后端技术有哪些. 纵观整个互联网技术体系再 ...

  8. (架构)后端技术体系框架

    1.后端技术体系框架 使用Java后端技术的目的就是构建业务应用,为用户提供在线或者离线服务.因此,一个业务应用需要哪些技术.依赖哪些基础设施就决定了需要掌握的后端技术有哪些.纵观整个互联网技术体系再 ...

  9. 对标阿里P8的MyBatis源码解析文档,面试/涨薪两不误,已献出膝盖

    移动互联网的特点是大数据.高并发,对服务器往往要求分布式.高性能.高灵活等,而传统模式的Java数据库编程框架已经不再适用了. 在这样的背景下,一个Java的持久框架MyBatis走入了我们的世界,它 ...

最新文章

  1. .NetCore微服务Surging新手傻瓜式 入门教程 学习日志---结构简介(二)
  2. ssm三大框架工作原理_蒸发器最常见的三大工作原理
  3. 计算机控制系统a卷-答案,计算机控制系统2010-2011年试题A答案
  4. OSTaskDelReq()--请求删除任务函数
  5. 北邮 复习 软件工程_软件工程专业最厉害的32所大学,共分4个档次,第一档当之无愧!...
  6. 如何使用Java将字符串保存到文本文件?
  7. [机器学习] 机器学习中所说的“线性模型”是个什么东西?
  8. HDU 5834 Magic boy Bi Luo with his excited tree 树形DP
  9. [20150204]关于位图索引4.txt
  10. @scheduled注解配置时间_《SpringBoot整合redis、Scheduled/quartz定时任务》
  11. 示波器上1G/S 100MHZ的含义
  12. Win10编译和测试libModbus
  13. (超详细) eclispe如何连接SQL Server2019(通过JDBC驱动包连接)
  14. python判断是否回文_Python语言判断输入的是否是回文数的方法
  15. 光学设计ZEMAX——什么是MF、RMS均方根点半径
  16. Linux高可用之heartbeat
  17. web前端期末大作业 HTML+CSS+JavaScript web课程设计网页规划与设计 企业网站制作
  18. android登陆界面ui设计,UI设计师必备技能:常用字体规范
  19. OpenCV中如何保存Mat矩阵
  20. 直播系统程序,云豹直播提供优质直播程序及云服务

热门文章

  1. [你必须知道的css系列]第一回:丰富的利器终结篇:选择符的组合关系及选择符总结...
  2. 电脑控制苹果手机_必备神器,电脑控制手机
  3. python中加入绝对路径_理解Python中的绝对路径和相对路径
  4. 1. 观察者模式总结(C++)
  5. 33 -jQuery 属性操作,文档操作(未完成)
  6. spring boot 读取 application.properties 初始化bean
  7. 第五章 Response(JavaTM Servlet 规范3.1 )
  8. LeetCode OJ - Populating Next Right Pointers in Each Node II
  9. modprobe:FATAL: could not load /lib/modules/2.6.35-22-generic/modules.dep No such file or directory
  10. Go学习笔记—标准库Context