前言
在GitHub Fork一份MyBatis源码后,我们在IDE中打开,运行测试用例AutoConstructorTest类中的fullyPopulatedSubject()方法,为了找到熟悉的感觉,我在同级目录的AutoConstructorMapper类和AutoConstructorMapper.xml文件对应添加了一个findById的查询。
加载全局配置文件流程
Tips:可以用Debug的模式来运行来打断点,看看Configuration中的值
1.加载全局配置文件mybatis-config.xml
try (Reader reader = Resources.getResourceAsReader("org/apache/ibatis/autoconstructor/mybatis-config.xml")) {
// 调用 #1
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
}
2.SqlSessionFactoryBuilder类中生成SqlSessionFactory
// #1
public SqlSessionFactory build(Reader reader) {
// 调用#2
return build(reader, null, null);
}
// #2
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
// 调用#3 parser.parse()
// 调用#4
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.
}
}
}
3.XMLConfigBuilder类中解析Configuration
// #3
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each MyXMLConfigBuilder can only be used once.");
}
parsed = true;
// 调用#5
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
// #5 XPathParser解析器会解析各种标签
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);
}
}
4.获取Configuration对象
经过以上几个步骤就会得到Configuration这个超级复杂的核心对象。
如图所示,拿其中mappedStatements来说,是个Map结构,它里面的key存储的就是*Mapper.xml中select/insert/update/delete标签中的id值,这里我们看findById,里面的mappedStatement存储这个关于这个statement的各种信息,statement的id由namespace+标签中的id来保证唯一性,具体细节可以打个断点查看下。
dataSource也正是我们从mybatis-config.xml文件中加载到的数据源配置项。
5.通过Configuration获取到SqlSessionFactory
// #4
public SqlSessionFactory build(Configuration config) {
// 使用DefaultSqlSessionFactory创建
return new DefaultSqlSessionFactory(config);
}
小结
本篇通过MyBatis提供的AutoConstructorTest测试类,我们跟踪了下全局配置文件的加载流程,xml中配置的一个
本篇只是粗略的探讨了几个主要的类:
- SqlSessionFactoryBuilder
- XMLConfigBuilder
- Configuration
- XPathParser
- SqlSessionFactory
但其实在XMLConfigBuilder中解析各个标签用到的XNode和其他一些类就没有去关心了或者说不是本篇的重点,正如第一篇讲到,把控好主线才不容易走丢。
请你相信我所说的都是错的