MyBatis
是最喜欢的框架,他的灵活性、可扩展性目前来说是最实用的,与其同类型的框架或多或少都有一些几乎让人无法忍受的缺点,目前在 MyBatis
中还没有发现令笔者无法忍受的弊端。
MyBatis
是以 SQLSessionFactory
为中心进行构建的。SQLSessionFactory
的主要任务是创建 SQLSession
。SQLSession
是实际数据库交互的核心部分。MyBatis
提供了两种模式去创建 SQLSessionFactory
:一种是XML方式,这是笔者推荐的方式;另一种是代码的方式。能够使用配置文件的时候,我们要尽量的使用配置文件,这样一方面可以避免硬编码,一方面方便日后配置人员的修改,避免重复编译代码。
接下来将一点一点的解读 MyBatis
,为了方便解读我们需要 首先 Fork MyBatis
的源码到我们自己的 Github 空间,还要创建一个用于测试的项目mybatis-learn。
创建测试项目
入口 创建SQLSessionFactory
接下来我们深入剖析一下,SQLSessionFactory
是如何被构建的
public class SqlSessionFactoryTest {
Logger logger = LoggerFactory.getLogger(SqlSessionFactoryTest.class) ;
@Test
public void testCreateSessionFactory() throws Exception {
String resource = "mybatis-config.xml" ;
InputStream inputStream = Resources.getResourceAsStream(resource) ;
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream) ;
logger.info(sqlSessionFactory.toString());
}
}
在第7
行代码SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream) ;
中可以看到 SQLSessionFactory
根据 mybatis-config.xml
完成了工厂类的构建。这个将是学习的入口。我们看一下实现代码
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.
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
通过第3
、4
行代码我们可以看见我们的配置信息通过 XMLCongfigBuilder
对象的parse
方法被解析成了Configuration
类对象,这个类对象包含了各种配置项很重要,它将存在于整个MyBatis
的生命周期中,一遍重复读取和运用。
最终创建了一个 DefaultSqlSessionFactory
对象,在 MyBatis
中提供了两个SQLSessionFactory
的实现类,DefaultSqlSessionFactory
和 SqlSessionManager
。不过SQLSessionManager
目前还没有使用,MyBatis
中目前使用的是DefaultSqlSessionFactory
。让我们看看他们的关系图
配置解析 XMLConfigBuilder.parseConfiguration(XNode root)
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
根据我们传入的参数我们最终通过 XMLConfigBuilder.parseConfiguration
将相关配置放到 Configuration
对象中,它将存在于整个MyBatis
的生命周期中,一遍重复读取和运用。
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
private void parseConfiguration(XNode root) {
try {
// issue #117 read properties first
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
loadCustomLogImpl(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
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);
}
}
parseConfiguration(XNode root)
XNode root
参数为将mybatis-config.xml
对象解析后的对象,即我们的配置项。
解析配置的系统变量
propertiesElement(root.evalNode(“properties”));
Properties settings = settingsAsProperties(root.evalNode(“settings”));
解析配置的文件加载系统
loadCustomVfs(settings);
解析配置使用的日志系统
loadCustomLogImpl(settings);
解析配置的别名
typeAliasesElement(root.evalNode(“typeAliases”));
解析配置的插件
pluginElement(root.evalNode(“plugins”));
解析自定义对象工厂
objectFactoryElement(root.evalNode(“objectFactory”));
解析自定义对象封装工厂
objectWrapperFactoryElement(root.evalNode(“objectWrapperFactory”));
解析自定义反射工厂
reflectorFactoryElement(root.evalNode(“reflectorFactory”));
解析自定义系统设置项
settingsElement(settings);
读取数据库配置信息
environmentsElement(root.evalNode(“environments”));
设置当前使用数据库类型
databaseIdProviderElement(root.evalNode(“databaseIdProvider”));
设置自定义数据类型处理类
typeHandlerElement(root.evalNode(“typeHandlers”));
解析SQL配置文件
mapperElement(root.evalNode(“mappers”));*