上篇文章 Mybatis系列(一)环境搭建,写了一个demo,大致了解了整个项目的流程。本节我们就来看看Mybatis的这么配置文件是如何实现的。
一、Mybatis入口
看一下上节的Test类
public static SqlSessionFactory getSessionFactory(){
SqlSessionFactory sqlSessionFactory = null;
String resource = "mybatis-config.xml";
try {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(resource));
} catch (IOException e) {
e.printStackTrace();
}
return sqlSessionFactory;
}
Test类是通过SqlSessionFactoryBuilder去创建的SqlSessionFactory,然后又通过SqlSessionFactory创建SqlSession,可见SqlSessionFactoryBuilder是Mybatis代码的入口,我们就先从它入手。
二、SqlSessionFactoryBuilder源码
public class SqlSessionFactoryBuilder {
public SqlSessionFactoryBuilder() {
}
//Reader读取mybatis配置文件,传入构造方法
//除了Reader外,mybatis也提供了inputStream作为参数的构造方法
public SqlSessionFactory build(Reader reader) {
return this.build((Reader)reader, (String)null, (Properties)null);
}
//mybatis配置文件 + environment
public SqlSessionFactory build(Reader reader, String environment) {
return this.build((Reader)reader, environment, (Properties)null);
}
//mybatis配置文件 + properties
public SqlSessionFactory build(Reader reader, Properties properties) {
return this.build((Reader)reader, (String)null, properties);
}
//mybatis配置文件 + environment + properties,其实不管传入多少个参数,最终都是通过build方法创建SqlSessionFactory
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
SqlSessionFactory var5;
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
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(InputStream inputStream) {
return this.build((InputStream)inputStream, (String)null, (Properties)null);
}
public SqlSessionFactory build(InputStream inputStream, String environment) {
return this.build((InputStream)inputStream, environment, (Properties)null);
}
public SqlSessionFactory build(InputStream inputStream, Properties properties) {
return this.build((InputStream)inputStream, (String)null, properties);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
SqlSessionFactory var5;
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException var13) {
}
}
return var5;
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
}
由上可以看出:
- Mybatis通过I/O流获取XML文件,字节流Reader和字符流InputStream两种方式均可。
- 每种读取方法都有多个重载方法,用来支持多种参数组合
- 但是最终都调用
build(Configuration config)
方法,返回DefaultSqlSessionFactory对象
通过源码,我们可以看到SqlSessionFactoryBuilder通过XMLConfigBuilder去解析我们传入mybatis的配置文件
三、XMLConfigBuilder源码
//mybatis配置文件解析
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
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配置文件解析
public Configuration parse() {
if (this.parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
} else {
this.parsed = true;
//根节点configuration
this.parseConfiguration(this.parser.evalNode("/configuration"));
return this.configuration;
}
}
//此方法就是解析configuration节点下的子节点
//由此也可看出,我们在configuration下面能配置的节点为以下10个节点
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.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);
}
}
通过以上源码可以看到,mybatis配置文件中:
-
对Mybatis配置文件XML解析需要new一个XMLConfigBuilder对象。
-
调用解析器的parse()方法,解析XML文件信息,并返回一个Configuration对象,Configuration对象包含XML对应的子节点
-
configuration为根节点,在configuration节点下,有10个子节点,分别是:properties、typeAliases、plugins、objectFactory、objectWrapperFactory、settings、environments、databaseIdProvider、typeHandlers、mappers。
-
SqlSessionFactoryBuilder最终返回的是一个 DefaultSqlSessionFactory对象。
四、mybatis核心组件
这节我们主要介绍了mybatis核心组件之一的SqlSessionFactoryBuilder组件,它时如何解析mybatis的xml配置文件。mybatis核心组件主要包含:
- SqlSessionFactoryBuilder(构造器):他会根据配置或者代码生成SqlSessionFactory,采用的是分步构建的Builder模式。
- SqlSessionFactory(工厂接口):依靠它来生成SqlSession,使用的是工厂模式。
- SqlSession(会话):一个既可以发送SQL执行返回结果,也可以获取Mapper的接口,在现有的技术中,一般我们会让其在业务逻辑代码中“消失”,而使用的是Mybatis提供的SQL
Mapper接口编程技术,它能提高代码的可读性和可维护性。 - SQL
Mapper(映射器):Mybatis新设计存在的组件,它由一个java接口和XML文件(或注解)构成,需要给出对应的SQL和映射规则。它负责发送SQL去执行,并返回结果。
以及刚刚提到的configuration下的子节点,我们下节再深入介绍。