# MyBatis源码-配置文件加载
这一节我们来看看 MyBatis 如何读取配置文件
# 介绍
MyBatis 如果集成 springboot 当中,可以进行 yml
或 properties
进行相关配置,这里我们不基于 springboot 进行演示是为了减少一些干扰。我们使用原生的 MyBatis 配置形式进行源码的解读。
先看xml
配置文件
# mybatis-config.xml 配置内容
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="com.github.yeecode.mybatisdemo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/yeecode?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/github/yeecode/mybatisdemo/UserMapper.xml"/>
</mappers>
</configuration>
# 测试代码
public static void main(String[] args) {
// 第一阶段:MyBatis的初始化阶段
String resource = "mybatis-config.xml";
// 得到配置文件的输入流
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
// 得到SqlSessionFactory
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
// 第二阶段:数据读写阶段
try (SqlSession session = sqlSessionFactory.openSession()) {
// 找到接口对应的实现
UserMapper userMapper = session.getMapper(UserMapper.class);
// 组建查询参数
User userParam = new User();
userParam.setSchoolName("Sunny School");
// 调用接口展开数据库操作
List<User> userList = userMapper.queryUserBySchoolName(userParam);
// 打印查询结果
for (User user : userList) {
System.out.println("name : " + user.getName() + " ; email : " + user.getEmail());
}
}
}
# 加载配置文件代码分析
通过上面测试代码看到,传入一个配置文件名称获取一个输出流。拿到输出流从而构建了一个 SqlSessionFactory
对象。
我们先来看看 MyBatis 如何读取配置文件的,读取配置文件是这句代码进行的 getResourceAsStream(resource, getClassLoaders(classLoader))
, resource
就是配置文件的名称,点开这个方法一路点下去找到主要的源代码:
//首先我们先看下 classLoader的方法实现,加载配置文件默认是从下面5个classLoader来加载,如果我们没有指定具体的classLoader,
//那第一个classLoader就是空
ClassLoader[] getClassLoaders(ClassLoader classLoader) {
return new ClassLoader[]{
classLoader,
defaultClassLoader,
Thread.currentThread().getContextClassLoader(),
getClass().getClassLoader(),
systemClassLoader};
}
//classLoader 的值就是上面 getClassLoaders 方法的返回值
InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
//resource 就是我们传递的配置文件名称 mybatis-config.xml
//classLoader 是从哪个路径下加载配置文件,
for (ClassLoader cl : classLoader) {
if (null != cl) {
// 先尝试从传递的路径查找资源
InputStream returnValue = cl.getResourceAsStream(resource);
// 如果查找不到,加 '/' 再次尝试
if (null == returnValue) {
returnValue = cl.getResourceAsStream("/" + resource);
}
if (null != returnValue) {
return returnValue;
}
}
}
return null;
}
# 文件流创建配置类
上面已经获取到了配置文件的文件流,然后开始构建 SqlSessionFactory
,主要关注的是解析 xml 文件。详细的解析,请看下一节。
// 得到SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//构建配置类
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
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.
}
}
}
//把流解析为配置
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
//从configuration 节点开始解析
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
//解析xml 各个节点 比如:mappers environments(数据源) typeAliases
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
propertiesElement(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 #631
environmentsElement(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源码详解》