1.1 配置文件解析过程分析
我们在使用MyBatis的时候,第一步要做的事情一般是根据配置文件构建SqlSessionFactory对象,相关代码大致如下:
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
在上面的代码中,我们会先加载配置文件,获取一个输入流。然后通过SqlSessionFactoryBuilder对象的build()方法构建SqlSessionFactory对象。下面我们来看一下这个方法的代码:
//SqlSessionFactoryBuilder类
public SqlSessionFactory build(Reader reader) {
return this.build((Reader)reader, (String)null, (Properties)null);
}
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
SqlSessionFactory var5;
try {
//创建配置文件解析器,XPath解析
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
//调用parse方法解析配置文件,生成Configuration对象
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException var13) {
;
}
}
return var5;
}
public SqlSessionFactory build(Configuration config) {
//创建DefaultSqlSessionFactory
return new DefaultSqlSessionFactory(config);
}
从上面的代码我们可以看出MyBatis配置文件是通过XMLConfigBuilder进行解析的。这次我们看一下XMLConfigBuilder的parse方法,如下:
//XMLConfigBuilder类
public Configuration parse() {
if(this.parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
} else {
this.parsed = true;
//解析配置
this.parseConfiguration(this.parser.evalNode("/configuration"));
return this.configuration;
}
}
注意XPath表达式——/configuration。这个表达式代表的是MyBatis配置文件的<configuration>节点,这里通过XPath选定这个节点,并传递给parseConfiguration方法。
private void parseConfiguration(XNode root) {
try {
this.propertiesElement(root.evalNode("properties"));
this.typeAliasesElement(root.evalNode("typeAliases"));
this.pluginElement(root.evalNode("plugins"));
this.objectFactoryElement(root.evalNode("objectFactory"));
this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
this.reflectionFactoryElement(root.evalNode("reflectionFactory"));
this.settingsElement(root.evalNode("settings"));
this.environmentsElement(root.evalNode("environments"));
this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
this.typeHandlerElement(root.evalNode("typeHandlers"));
this.mapperElement(root.evalNode("mappers"));
} catch (Exception var3) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
}
}
到此,一个完整的配置解析过程就出来了,每个节点的解析逻辑均封装在相应的方法中。