前言
上一篇我们通过一个简单的例子了解了基于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实例的过程)过程就比较清晰了:
- 首先创建XMLConfigBuilder 实例,然后创建了 Configuration 实例,顺便把解析XML文件内容的工具类也创建好
- 在 XMLConfigBuilder 当中解析 Configuration的每一个节点,并设置到Configuration当中去
- 最后返回 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 配置文件中支持的节点类型包含如下内容,先写到这里,下篇文章依次来了解下每一项的解析过程.
- properties 属性
- settings 设置
- typeAliases 类型命名
- plugins 插件
- objectFactory 对象工厂
- objectWrapperFactory
- reflectionFactory
- environments 环境
- databaseIdProvider 数据库厂商标识
- typeHandlers 类型处理器
- mappers 映射器
网友评论