前言
上一篇我們通過一個(gè)簡(jiǎn)單的例子了解了基于XML配置文件的方式初始化Mybatis的過程,毫不夸張的說,MyBatis初始化的過程,就是創(chuàng)建 Configuration對(duì)象的過程。而在構(gòu)建SqlSessionFactory的過程中,生成了XMLConfigBuilder實(shí)例對(duì)象,所以我們就先從XMLConfigBuilder說起。
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.
}
}
}
XMLConfigBuilder
首先我們先看下XMLConfigBuilder實(shí)例的創(chuàng)建過程,如上述所示,入?yún)閕nputStream,environment和properties, 如下所示,是通過生成XPathParser實(shí)例后調(diào)用私有構(gòu)造函數(shù)來生成的。XPathParser封裝了JDK中的Document和XPath對(duì)象,其實(shí)就是一個(gè)工具類,主要用來解析XML文件內(nèi)容的。
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
// 私有構(gòu)造函數(shù),對(duì)應(yīng)上面代碼中的this
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;
}
其實(shí)分析到這,Mybatis的初始化(其實(shí)就是創(chuàng)建Configuration實(shí)例的過程)過程就比較清晰了:
- 首先創(chuàng)建XMLConfigBuilder 實(shí)例,然后創(chuàng)建了 Configuration 實(shí)例,順便把解析XML文件內(nèi)容的工具類也創(chuàng)建好
- 在 XMLConfigBuilder 當(dāng)中解析 Configuration的每一個(gè)節(jié)點(diǎn),并設(shè)置到Configuration當(dāng)中去
- 最后返回 Configuration 實(shí)例,并以其為入殘參,來生成SqlSessionFactory實(shí)例
// 解析 Configuration的每一個(gè)節(jié)點(diǎn)
private void parseConfiguration(XNode root) {
try {
Properties settings = settingsAsPropertiess(root.evalNode("settings"));
propertiesElement(root.evalNode("properties"));
loadCustomVfs(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectionFactoryElement(root.evalNode("reflectionFactory"));
settingsElement(settings);
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);
}
}
BaseBuilder
XMLConfigBuilder繼承了 BaseBuilder,事實(shí)上,其他所有解析XML的Builder都繼承了這個(gè)類。下面是BaseBuilder的大致結(jié)構(gòu),由此看出,Configuration實(shí)例其實(shí)是存放在BaseBuilder中的。
public abstract class BaseBuilder {
protected final Configuration configuration;
protected final TypeAliasRegistry typeAliasRegistry;
protected final TypeHandlerRegistry typeHandlerRegistry;
public BaseBuilder(Configuration configuration) {
this.configuration = configuration;
this.typeAliasRegistry = this.configuration.getTypeAliasRegistry();
this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry();
}
...... // 此處省略了很多方法
}
下圖是BaseBuilder的實(shí)現(xiàn)依賴圖,你會(huì)發(fā)現(xiàn),基本上所有解析XML的類都需要即成這個(gè)基類,其中的幾個(gè)類(Mapper相關(guān)的)以后會(huì)詳細(xì)描述。
XMLConfigBuilder 的具體工作
上問我們了解到,繼承了 BaseBuilder 的 XMLConfigBuilder, 其實(shí)是Myabtis初始化的真正入口,那 XMLConfigBuilder 實(shí)際上都做了些什么工作呢?其實(shí)都在 XMLConfigBuilder 實(shí)例的parse方法內(nèi)。
// parse方法
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
從代碼上可以看出,其實(shí)parse()方法也是拋磚引玉的方法,真正干活的其實(shí)是 parseConfiguration 方法
private void parseConfiguration(XNode root) {
try {
Properties settings = settingsAsPropertiess(root.evalNode("settings"));
//issue #117 read properties first
propertiesElement(root.evalNode("properties"));
loadCustomVfs(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectionFactoryElement(root.evalNode("reflectionFactory"));
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 配置文件之解析詳解
從上面的 parseConfiguration 方法可以看出,Mybatis 配置文件中支持的節(jié)點(diǎn)類型包含如下內(nèi)容,先寫到這里,下篇文章依次來了解下每一項(xiàng)的解析過程.
- properties 屬性
- settings 設(shè)置
- typeAliases 類型命名
- plugins 插件
- objectFactory 對(duì)象工廠
- objectWrapperFactory
- reflectionFactory
- environments 環(huán)境
- databaseIdProvider 數(shù)據(jù)庫廠商標(biāo)識(shí)
- typeHandlers 類型處理器
- mappers 映射器