Mybatis 源码之加载配置

通过 SqlSessionFactoryBuilder 加载配置

定位: org.apache.ibatis.session.SqlSessionFactoryBuilder#build
作用: 解析xml文件, 并生成配置项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
// 准备工作:将配置文件加载到内存中并生成一个document对象 ,同时初始化Configuration对象
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.
}
}
}

xml文件解析器 XMLConfigBuilder

定位: org.apache.ibatis.builder.xml.XMLConfigBuilder#XMLConfigBuilder
作用: 解析 xml 配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
  public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
// 上面的6个构造函数最后都会合流到这个函数,传入XPathParser
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
// 调用父类初始化configuration
super(new Configuration());
// 错误上下文设置成SQL Mapper Configuration(xml文件配置)
ErrorContext.instance().resource("SQL Mapper Configuration");
// 将Properties全部设置到configuration里面去
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
// 解析配置
public Configuration parse() {
// 根据parsed变量的值判断是否已经完成了对mybatis-config.xml配置文件的解析
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
// 在mybatis-config.xml配置文件中查找<configuration>节点,并开始解析
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
// 解析配置
private void parseConfiguration(XNode root) {
try {
// issue #117 read properties first
// 解析properties
propertiesElement(root.evalNode("properties"));
// 解析settings
Properties settings = settingsAsProperties(root.evalNode("settings"));
// 设置vfsImpl字段
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);//设置具体的属性到configuration对象
// read it after objectFactory and objectWrapperFactory issue #631
// 环境
environmentsElement(root.evalNode("environments"));
// databaseIdProvider
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);
}
}
private void environmentsElement(XNode context) throws Exception {
if (context != null) {
// 未指定XMLConfigBuilder.environment字段,则使用default属性
if (environment == null) {
environment = context.getStringAttribute("default");
}
// 遍历子节点
for (XNode child : context.getChildren()) {
String id = child.getStringAttribute("id");
// 与XmlConfigBuilder.environment字段匹配
if (isSpecifiedEnvironment(id)) {
// 创建TransactionFactory
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
// 创建DataSourceFactory和DataSource
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
DataSource dataSource = dsFactory.getDataSource();
// 创建Environment
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
// 将Environment对象记录到Configuration.environment字段中
configuration.setEnvironment(environmentBuilder.build());
break;
}
}
}
}
private DataSourceFactory dataSourceElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
Properties props = context.getChildrenAsProperties();
// 根据type="POOLED"解析返回适当的DataSourceFactory
DataSourceFactory factory = (DataSourceFactory) resolveClass(type).getDeclaredConstructor().newInstance();
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a DataSourceFactory.");
}
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
// 处理mapper子节点
for (XNode child : parent.getChildren()) {
// package子节点
if ("package".equals(child.getName())) {
// 自动扫描包下所有映射器
String mapperPackage = child.getStringAttribute("name");
// 扫描指定的包,并向mapperRegistry注册mapper接口
configuration.addMappers(mapperPackage);
} else {
// 获取mapper节点的resource、url、class属性,三个属性互斥
String resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
// 如果mapper节点指定了resource或者url属性,则创建XmlMapperBuilder对象,并通过该对象解析resource或者url属性指定的mapper配置文件
if (resource != null && url == null && mapperClass == null) {
// 使用类路径
ErrorContext.instance().resource(resource);
try (InputStream inputStream = Resources.getResourceAsStream(resource)) {
// 创建XMLMapperBuilder对象,解析映射配置文件
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
mapperParser.parse();
}
} else if (resource == null && url != null && mapperClass == null) {
// 使用绝对url路径
ErrorContext.instance().resource(url);
try (InputStream inputStream = Resources.getUrlAsStream(url)) {
// 创建XMLMapperBuilder对象,解析映射配置文件
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
mapperParser.parse();
}
} else if (resource == null && url == null && mapperClass != null) {
// 如果mapper节点指定了class属性,则向MapperRegistry注册该mapper接口
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 解析器

定位: org.apache.ibatis.builder.xml.XMLMapperBuilder
作用: 用户解析 mapper 节点, 并封装成 Mapper 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 解析
public void parse() {
// 判断是否已经加载过该映射文件
if (!configuration.isResourceLoaded(resource)) {
// 处理mapper节点
configurationElement(parser.evalNode("/mapper"));
// 将resource添加到Configuration.loadedResources集合中保存,他是hashset类型的集合,其中记录了已经加载过的映射文件
configuration.addLoadedResource(resource);
// 绑定映射器到namespace
bindMapperForNamespace();
}

// 处理ConfigurationElement方法中解析失败的resultMap节点
parsePendingResultMaps();
// 处理ConfigurationElement方法中解析失败的cache-ref节点
parsePendingCacheRefs();
// 处理ConfigurationElement方法中解析失败的SQL语句节点
parsePendingStatements();
}

Mybatis 配置项 Configuration

定位: org.apache.ibatis.session.Configuration#Configuration
作用: 解析后的参数配置项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Configuration {
// 脚本语言注册器
protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();
//类型别名注册机
protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
public Configuration() {
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
// 。。。 省略别名注册

languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
languageRegistry.register(RawLanguageDriver.class);
}
}