1. 准备工作
编写测试代码(具体请参考《Mybatis入门示例》),设置断点,以Debug模式运行,具体代码如下:
String resource = "mybatis.cfg.xml";
Reader reader = Resources.getResourceAsReader(resource);
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader);
SqlSession session = ssf.openSession();
2.源码分析
我们此次就对上面的代码进行跟踪和分析,let's go。
首先我们按照顺序先看看第一行和第二行代码,看看它主要完成什么事情:
String resource = "mybatis.cfg.xml";
Reader reader = Resources.getResourceAsReader(resource);
读取Mybaits的主配置配置文件,并返回该文件的输入流,我们知道Mybatis所有的SQL语句都写在XML配置文件里面,所以第一步就需要读取这些XML配置文件,这个不难理解,关键是读取文件后怎么存放。
我们接着看第三行代码(如下),该代码主要是读取配置文件流并将这些配置信息存放到Configuration类中。
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader);
SqlSessionFactoryBuilder的build的方法如下:
public SqlSessionFactory build(Reader reader) {
return build(reader, null, null);
}
其实是调用该类的另一个build方法来执行的,具体代码如下:
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
我们重点看一下里面两行:
//创建一个配置文件流的解析对象XMLConfigBuilder,其实这里是将环境和配置文件流赋予解析类
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
// 解析类对配置文件进行解析并将解析的内容存放到Configuration对象中,并返回SqlSessionFactory
return build(parser.parse());
这里的XMLConfigBuilder初始化其实调用的代码如下:
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;
}
XMLConfigBuilder的parse方法执行代码如下:
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each MapperConfigParser can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
解析的内容主要是在parseConfiguration方法中,它主要完成的工作是读取配置文件的各个节点,然后将这些数据映射到内存配置对象Configuration中,我们看一下parseConfiguration方法内容:
private void parseConfiguration(XNode root) {
try {
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
propertiesElement(root.evalNode("properties"));
settingsElement(root.evalNode("settings"));
environmentsElement(root.evalNode("environments"));
typeHandlerElement(root.evalNode("typeHandlers"));
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
最后的build方法其实是传入配置对象进去,创建DefaultSqlSessionFactory实例出来. DefaultSqlSessionFactory是SqlSessionFactory的默认实现.
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
最后我们看一下第四行代码:
SqlSession session = ssf.openSession();
通过调用DefaultSqlSessionFactory的openSession方法返回一个SqlSession实例,我们看一下具体是怎么得到一个SqlSession实例的。首先调用openSessionFromDataSource方法。
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
下面我们看一下openSessionFromDataSource方法的逻辑:
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Connection connection = null;
try {
//获取配置信息里面的环境信息,这些环境信息都是包括使用哪种数据库,连接数据库的信息,事务
final Environment environment = configuration.getEnvironment();
//根据环境信息关于数据库的配置获取数据源
final DataSource dataSource = getDataSourceFromEnvironment(environment);
//根据环境信息关于事务的配置获取事务工厂
TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
connection = dataSource.getConnection();
if (level != null) {
//设置连接的事务隔离级别
connection.setTransactionIsolation(level.getLevel());
}
//对connection进行包装,使连接具备日志功能,这里用的是代理。
connection = wrapConnection(connection);
//从事务工厂获取一个事务实例
Transaction tx = transactionFactory.newTransaction(connection, autoCommit);
//从配置信息中获取一个执行器实例
Executor executor = configuration.newExecutor(tx, execType);
//返回SqlSession的一个默认实例
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeConnection(connection);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
传入参数说明:
(1)ExecutorType:执行类型,ExecutorType主要有三种类型:SIMPLE, REUSE, BATCH,默认是SIMPLE,都在枚举类ExecutorType里面。
(2)TransactionIsolationLevel:事务隔离级别,都在枚举类TransactionIsolationLevel中定义。
(3)autoCommit:是否自动提交,主要是事务提交的设置。
DefaultSqlSession是SqlSession的实现类,该类主要提供操作数据库的方法给开发人员使用。
这里总结一下上面的过程,总共由三个步骤:
步骤一:读取Ibatis的主配置文件,并将文件读成文件流形式(InputStream)。
步骤二:从主配置文件流中读取文件的各个节点信息并存放到Configuration对象中。读取mappers节点的引用文件,并将这些文件的各个节点信息存放到Configuration对象。
步骤三:根据Configuration对象的信息获取数据库连接,并设置连接的事务隔离级别等信息,将经过包装数据库连接对象SqlSession接口返回,DefaultSqlSession是SqlSession的实现类,所以这里返回的是DefaultSqlSession,SqlSession接口里面就是对外提供的各种数据库操作。
分享到:
相关推荐
《深入理解Spring与Dubbo整合原理与源码分析:从启动类配置到注解解析》是一本专注于探讨Spring和Dubbo两大开源框架整合的技术书籍。本文将基于书中的主题,结合标签“spring”、“dubbo”和“软件/插件”,深入解析...
10. **初始化文件系统**:挂载根文件系统,这是系统运行所必需的,用于存储系统程序和配置文件。 11. **启动系统服务**:启动内核模块和服务,如网络协议栈、系统日志等。 12. **过渡到用户空间**:最后,通过启动...
- Tomcat会读取`conf/catalina.properties`、`conf/server.properties`等配置文件,获取服务器的默认设置。 - `webapps`目录下的每个应用都有对应的`WEB-INF/web.xml`,定义了应用的部署信息,Tomcat会逐一解析...
XML(eXtensible Markup Language)文件是一种结构化数据存储格式,广泛应用于Web服务、配置文件、数据交换和文档存储等领域。它允许自定义标签来描述数据内容,使得数据具有可读性和易于处理的特性。在本文中,我们...
- 一个主程序,用于初始化SAX解析器并设置自定义的`ContentHandler`。 - 可能还有一个XML文件作为输入,供解析器读取。 使用SAX解析XML的优点在于效率高,适用于处理大型XML文件。但缺点是需要编写更多代码来处理...
4. 读取配置文件:包括读取capture filter和display filter文件,分别保存在capture_filter和display_filter全局变量中。 5. 读取disabled protocols文件:保存全局变量global_disabled_protos和disabled_protos中。...
在Spring框架中,Bean的初始化是一个至关重要的过程,它涉及到从XML配置文件或者注解中读取Bean的定义,解析并构建Bean实例。本篇文章主要分析了Spring如何通过`ClassPathXmlApplicationContext`来启动和初始化Bean...
源码层面,配置文件的读取通常在程序初始化阶段进行,通过专门的配置模块加载并解析。开发者需要关注配置文件加载的错误处理,确保即使配置文件出现问题,程序也能以某种降级模式正常运行。此外,源码中应有良好的...
例如,可能有`stm32f1xx_hal_conf.h`配置文件,它定义了外设时钟设置和其他硬件配置;`stm32f1xx_hal_sd.h`和`stm32f1xx_hal_sd.c`包含SD卡的HAL(Hardware Abstraction Layer,硬件抽象层)驱动,提供了易于使用的...
1. **初始化缓存**:首次读取XML文件时,将其完全解析并存储在内存中。 2. **文件状态监测**:记录XML文件最后修改的时间戳。 3. **数据读取**: - 如果请求数据且文件未被修改,则直接从缓存中获取。 - 如果文件...
这个过程涉及多个步骤,包括解析XML文件,创建Bean定义,以及实例化和初始化Bean。`AbstractBeanDefinitionReader`类是用于读取和解析XML文件的关键组件,它负责将XML配置转换为Spring可以理解的Bean定义。 值得...
- **init()方法**:这是一个可选步骤,开发者可以根据需要重写`init()`方法来完成必要的初始化工作,比如读取配置文件、设置环境变量等。 - **初始化参数**:通过部署描述符(web.xml)可以为Servlet提供初始化...
XML(eXtensible Markup Language)是一种用于标记数据的语言,广泛应用在互联网上,特别是在数据交换、配置文件和文档存储等领域。XML的结构清晰,易于人类阅读,并且机器也能方便地解析和生成。本资源提供了XML...
源码通常会包含初始化、读取、转换和校准的函数,你可以逐一分析理解其工作原理。 此外,由于STM32H743的运行温度较高,为了降低温度,可以采取以下措施: 1. 降低系统时钟频率:减小CPU的工作负荷,减少热量产生...
以下是一份详细的MATLAB串口读取数据的知识点解析: 1. **初始化串口**: - 首先,我们需要使用`comport`函数来获取可用的串口列表。例如,`comports()`会列出所有可用的串口。 - 选择一个串口,如COM1,然后使用...
通过对`wpa_supplicant`代码流程的详细分析,我们可以了解到这款工具是如何逐步初始化并为无线网络提供认证和密钥管理服务的。从操作系统环境的初始化、认证方法的注册、全局参数的配置,到驱动程序的选择与初始化、...
这个过程通常涉及到与读卡器的协议交互,可能包括初始化、选择卡、请求响应等步骤。具体命令会根据所使用的IC卡类型和读卡器型号有所不同,可能需要查阅相关的读卡器说明书或API文档。 读取IC卡卡号值的过程通常是...
源码解析中,会详细讲解Bean的定义方式,如XML配置、注解驱动和Java配置类,以及Bean的生命周期,包括初始化方法、后处理器、销毁方法等。 其次,时序图是理解系统间交互的重要工具。在Spring源码解析中,时序图...
4. **配置文件读取**:从外部配置文件读取日志文件的路径等信息,增强程序的灵活性和可维护性。 5. **资源管理**:正确地关闭和释放使用的资源,避免内存泄漏。 #### 核心方法解析 1. **构造函数与初始化**: `...