标签:Configuration 配置文件 核心 源码 MyBatis 解析 root evalNode
目录
mybatis与数据库进行交互有两种方式,一种传统方式,一种mapper代理方式。通过对两种方式的分析我们需要掌握以下内容:
- 传统方式
- MyBatis如何加载解析配置文件?
- MyBatis如何解析SQL、设置参数以及执行SQL的?
- MyBatis如何封装返回结果集?
- mapper代理方式
- MyBatis底层如何产生代理对象?
- 当代理对象调用方法时它又是如何执行到底层的JDBC代码的?
1 传统方式源码剖析
类似于Spring、MyBatis等灵活性和可拓展性都很高的开源框架都提供了很多配置项,开发人员需要在使用时提供相应的配置信息,实现相应的需求。MyBatis中的配置文件主要有两个,分别是mybatis-config.xml
和映射配置文件。现在主流的配置方式除了使用XML配置文件,还会配合注解进行配置。
1.1 初始化流程
Mybatis初始化的主要工作就是加载并解析mybatis-config.xml
配置文件、映射配置文件以及相关的注解信息。在引入了MyBatis依赖的项目中我们可以通过以下两行代码执行初始化操作。
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//这一行代码就是初始化的开始
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
Mybatis的初始化入口就是SqlSessionFactoryBuilder.build()方法。再来看看build()方法里做了什么。
// 1.我们最初调用的build
public SqlSessionFactory build(InputStream inputStream) {
//调用了重载方法
return build(inputStream, null, null);
}
// 2.调用的重载方法
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
// 创建 XMLConfigBuilder, XMLConfigBuilder是专门解析mybatis的配置文件的类
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
// 执行 XML 解析
// 创建 DefaultSqlSessionFactory 对象。parse()方法返回的是Configuration对象。
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.
}
}
}
从上面的源码可以看出,build()方法很简单,只是调用了一下重载的build()方法,具体细节可以看注释。接下来我们开始分析XMLConfigBuilder的parse()方法以及Configuration对象。MyBatis在初始化的时候,会将MyBatis的配置信息全部加载到内存中,使用Configuration对象实例来存储。Configuration对象的结构和xml配置文件几乎相同,也就是说XML文件中的properties
(属性)、setting
(设置)、typeAliases
(类型别名)和typeHandlers
(类型处理器)等配置标签在Configuration对象中都有对应的属性来封装它们。也就是说,初始化配置文件信息的本质就是创建Configuration对象,将解析的XML数据封装到Configuration内部属性中。
/**
* 解析 XML 成 Configuration 对象。
*
* @return Configuration 对象
*/
public Configuration parse() {
// 若已解析,抛出 BuilderException 异常
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
// 标记已解析
parsed = true;
///parser是XPathParser解析器对象,读取节点内数据,<configuration>是MyBatis配置文件中的顶层标签
// 解析 XML configuration 节点
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
/**
* 解析 XML
*
* 具体 MyBatis 有哪些 XML 标签,参见 《XML 映射配置文件》http://www.mybatis.org/mybatis-3/zh/configuration.html
*
* @param root 根节点
*/
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
// 解析 <properties /> 标签
propertiesElement(root.evalNode("properties"));
// 解析 <settings /> 标签
Properties settings = settingsAsProperties(root.evalNode("settings"));
// 加载自定义的 VFS 实现类
loadCustomVfs(settings);
// 解析 <typeAliases /> 标签
typeAliasesElement(root.evalNode("typeAliases"));
// 解析 <plugins /> 标签
pluginElement(root.evalNode("plugins"));
// 解析 <objectFactory /> 标签
objectFactoryElement(root.evalNode("objectFactory"));
// 解析 <objectWrapperFactory /> 标签
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
// 解析 <reflectorFactory /> 标签
reflectorFactoryElement(root.evalNode("reflectorFactory"));
// 赋值 <settings /> 到 Configuration 属性
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
// 解析 <environments /> 标签
environmentsElement(root.evalNode("environments"));
// 解析 <databaseIdProvider /> 标签
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
// 解析 <typeHandlers /> 标签
typeHandlerElement(root.evalNode("typeHandlers"));
// 解析 <mappers /> 标签
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
从源码中可以看到,程序是通过parseConfiguration()实现了对mybatis-config.xml
配置文件中的每个节点进行解析的,每个节点的解析过程都封装成了一个单独的方法,代码清爽简洁。
标签:Configuration,配置文件,核心,源码,MyBatis,解析,root,evalNode 来源: https://www.cnblogs.com/csh24/p/13567978.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。