Mybatis源碼淺析(二)

前言

上一篇我們通過一個簡單的例子了解了基于XML配置文件的方式初始化Mybatis的過程,毫不夸張的說,MyBatis初始化的過程,就是創建 Configuration對象的過程。而在構建SqlSessionFactory的過程中,生成了XMLConfigBuilder實例對象,所以我們就先從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實例的創建過程,如上述所示,入參為inputStream,environment和properties, 如下所示,是通過生成XPathParser實例后調用私有構造函數來生成的。XPathParser封裝了JDK中的Document和XPath對象,其實就是一個工具類,主要用來解析XML文件內容的。

public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}

// 私有構造函數,對應上面代碼中的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;
}

其實分析到這,Mybatis的初始化(其實就是創建Configuration實例的過程)過程就比較清晰了:

  1. 首先創建XMLConfigBuilder 實例,然后創建了 Configuration 實例,順便把解析XML文件內容的工具類也創建好
  2. 在 XMLConfigBuilder 當中解析 Configuration的每一個節點,并設置到Configuration當中去
  3. 最后返回 Configuration 實例,并以其為入殘參,來生成SqlSessionFactory實例
// 解析 Configuration的每一個節點
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,事實上,其他所有解析XML的Builder都繼承了這個類。下面是BaseBuilder的大致結構,由此看出,Configuration實例其實是存放在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的實現依賴圖,你會發現,基本上所有解析XML的類都需要即成這個基類,其中的幾個類(Mapper相關的)以后會詳細描述。


_
_

XMLConfigBuilder 的具體工作

上問我們了解到,繼承了 BaseBuilder 的 XMLConfigBuilder, 其實是Myabtis初始化的真正入口,那 XMLConfigBuilder 實際上都做了些什么工作呢?其實都在 XMLConfigBuilder 實例的parse方法內。

// parse方法
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}

從代碼上可以看出,其實parse()方法也是拋磚引玉的方法,真正干活的其實是 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 配置文件中支持的節點類型包含如下內容,先寫到這里,下篇文章依次來了解下每一項的解析過程.

  1. properties 屬性
  2. settings 設置
  3. typeAliases 類型命名
  4. plugins 插件
  5. objectFactory 對象工廠
  6. objectWrapperFactory
  7. reflectionFactory
  8. environments 環境
  9. databaseIdProvider 數據庫廠商標識
  10. typeHandlers 類型處理器
  11. mappers 映射器
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容