开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第30天,点击查看活动详情
前言
SqlSessionFactoryBean作为Mybatis中一个特别重要的类,在Spring集成Mybatis框架发挥了重要作用,我们很有必要写一篇文章来简要分析一下它都做了啥操作;
实现的接口
在SqlSessionFactoryBean中分别实现了三个接口:
1.FactoryBean<SqlSessionFactory>接口,表明SqlSessionFactoryBean用来生产SqlSessionFactory实例,主要方法看getObject();
2.InitializingBean接口,这是一个初始化功能,关键方法看afterPropertiesSet();
3.ApplicationListener<ApplicationEvent>接口,说明这是一个监听器,关注方法onApplicationEvent();
上面三个接口,我们重点看第二个InitializingBean接口,因为第一个接口和第三个接口的方法实现都特别简单:
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
this.afterPropertiesSet();
}
return this.sqlSessionFactory;
}
第一个接口直接返回sqlSessionFactory;
public void onApplicationEvent(ApplicationEvent event) {
if (this.failFast && event instanceof ContextRefreshedEvent) {
this.sqlSessionFactory.getConfiguration().getMappedStatementNames();
}
}
第三个接口事件监听做的事情基本可以不用管;所以下面剩下的就是第二个接口的处理逻辑了:
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.dataSource, "Property 'dataSource' is required");
Assert.notNull(this.sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
Assert.state(this.configuration == null && this.configLocation == null || this.configuration == null || this.configLocation == null, "Property 'configuration' and 'configLocation' can not specified with together");
this.sqlSessionFactory = this.buildSqlSessionFactory();
}
看代码就可以知道,afterPropertiesSet()方法只做了一件事情,那就是创建SqlSessionFactory;所有的创建逻辑全部都在buildSqlSessionFactory()方法中,创建出来的SqlSessionFactory后面通过第一个接口的getObject()方法返回给Spring IOC容器管理;
final Configuration targetConfiguration;
XMLConfigBuilder xmlConfigBuilder = null;
// 如果configuration不为空,那么targetConfiguration由configuration赋值
if (this.configuration != null) {
targetConfiguration = this.configuration;
if (targetConfiguration.getVariables() == null) {
targetConfiguration.setVariables(this.configurationProperties);
} else if (this.configurationProperties != null) {
targetConfiguration.getVariables().putAll(this.configurationProperties);
}
// 如果指定来mybatis的配置文件,那么targetConfiguration值来自于xml配置
} else if (this.configLocation != null) {
xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
targetConfiguration = xmlConfigBuilder.getConfiguration();
} else {
LOGGER.debug(
() -> "Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration");
// 否则就自己创建Configuration;
targetConfiguration = new Configuration();
Optional.ofNullable(this.configurationProperties).ifPresent(targetConfiguration::setVariables);
}
上面的代码说明了SqlSessionFactoryBean中的配置可以是两个来源,一个是通过Spring的方式自己配置configuration,另一个就是直接通过configLocation配置mybatis的xml配置文件;
Optional.ofNullable(this.objectFactory).ifPresent(targetConfiguration::setObjectFactory);
Optional.ofNullable(this.objectWrapperFactory).ifPresent(targetConfiguration::setObjectWrapperFactory);
Optional.ofNullable(this.vfs).ifPresent(targetConfiguration::setVfsImpl);
接下来就处理一些简单的属性,比如objectFactory、objectWrapperFactory、vfs等等;直至所有属性处理完毕,最后调用下面的build()方法完成SqlSessionFactory的构建:
this.sqlSessionFactoryBuilder.build(targetConfiguration);
小结
通过上述源码的分析,我们现在明白了SqlSessionFactoryBean其实就做了一件事情,那就是创建SqlSessionFactory;但是在创建SqlSessionFactory之前,其实是花了很大篇幅在处理targetConfiguration配置的,最终通过处理好的targetConfiguration构建出了sqlSessionFactory;