在 mybatis源码分析-环境搭建 一文中,我们的测试代码如下:
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
List<Dept> deptList = deptMapper.getAllDept();
System.out.println(deptList);
} finally {
sqlSession.close();
}
}
其中如何生成 InputStream
对象在 mybatis源码分析-配置文件加载 已经讲解。本次将探究 SqlSessionFactory
对象的生成,也就是下面这行代码执行了什么。
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
源码分析
首先上面那行代码,创建了一个 SqlSessionFactoryBuilder
对象,源码如下:
public class SqlSessionFactoryBuilder {
public SqlSessionFactoryBuilder() {
}
//省略其它代码
}
其次 SqlSessionFactoryBuilder
对象调用 build
方法,该方法源码如下:
public SqlSessionFactory build(InputStream inputStream) {
return this.build((InputStream)inputStream, (String)null, (Properties)null);
}
这个方法看来有重载方法,我们继续看其重载方法:
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 parser = new XMLConfigBuilder(inputStream, environment, properties);
这个构造函数将我们的配置文件转换为 XMLConfigBuilder
对象,这里面的逻辑十分复杂,我们暂且不深究。
return build(parser.parse());
这里有两处注意的地方,parser.parse()
返回一个Configuration
对象,这个对象保罗万千,暂时也不深究。此外build
方法的实现如下:
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
它返回了 DefaultSqlSessionFactory
对象,并且将 Configuration
对象赋值其属性,有源码为证:
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
//省略其它代码
}
由于 DefaultSqlSessionFactory
实现了 SqlSessionFactory
接口,那么
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
就水到渠成了。
本节不想讨论
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
和
return build(parser.parse());
这两行代码的实现,因为它们太复杂了。目前只需要理解:
- 第一行通过配置文件创建了一个
XMLConfigBuilder
对象 - 第二行通过
XMLConfigBuilder
对象的一个parse
方法将XMLConfigBuilder
对象转换为Configuration
对象,而该对象是DefaultSqlSessionFactory
必须要的属性。只有通过这个属性,才能实现SqlSessionFactory
中定义的接口方法。
源码设计思想
如果我们来实现上面的功能,一般人会怎么处理呢?
- 首先定义接口
package com.yefengyu.mybatis;
public interface SqlSessionFactory {
void test();
}
- 其次编写实现类
package com.yefengyu.mybatis;
import org.apache.ibatis.builder.xml.XMLConfigBuilder;
import org.apache.ibatis.session.Configuration;
import java.io.InputStream;
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private Configuration configuration = null;
public DefaultSqlSessionFactory(InputStream inputStream) {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream);
this.configuration = parser.parse();
}
@Override
public void test() {
//使用 configuration 完成相关功能
}
}
- 测试
package com.yefengyu.mybatis;
import org.apache.ibatis.io.Resources;
import java.io.IOException;
import java.io.InputStream;
public class Main {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new DefaultSqlSessionFactory(inputStream);
sqlSessionFactory.test();
}
}
这三段代码想模拟mybatis创建SqlSessionFactory
对象的过程,比如SqlSessionFactory
有一些接口 test
,其实现类 DefaultSqlSessionFactory
实现此方法需要 Configuration
对象,需要从 InputStream
通过构造函数传入并解析为 Configuration
对象。测试代码中直接使用 DefaultSqlSessionFactory
创建 SqlSessionFactory
对象。
这种方式的缺点:
- 首先如果有多个
SqlSessionFactory
实现的话,把InputStream
转换为Configuration
的过程在每个构造函数都会有。 - 其次客户端,也就是测试代码那块,必须要清楚
SqlSessionFactory
有哪些实现类,每个实现类的功能是什么,没有达到接口与实现的分离。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。