22.MyBatis入门系列(22) -MyBatis-Spring核心源码解析之SqlSessionFactoryBean
22.MyBatis入门系列(22) -MyBatis-Spring核心源码解析之SqlSessionFactoryBean
前言
在之前使用了mybatis的文档中,我们需要手动创建SqlSessionFactory对象来获取SqlSession,然后通过SqlSession获取mapper代理对象,进行数据库操作。
// 根据xml配置文件(全局配置文件)创建一个SqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 通过SqlSessionFactory获取SqlSession实例
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
在上篇文档中,我们在使用MyBatis-Spring进行了简单的案例演示,将SqlSessionFactory和Mapper代理对象交给了spring去创建和管理,其中重要的一步是注入了SqlSessionFactory ,代码如下:
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
// 创建SqlSessionFactoryBean对象
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
// 设置数据源
factoryBean.setDataSource(dataSource());
// SqlSessionFactoryBean 对象获取SqlSessionFactory,并装载到IOC中
return factoryBean.getObject();
}
接下里我们分析下SqlSessionFactoryBean。
SqlSessionFactoryBean实现的接口有哪些
SqlSessionFactoryBean实现了三个重要的Spring接口:
- FactoryBean< SqlSessionFactory>,
- InitializingBean
- ApplicationListener< ApplicationEvent>
1. FactoryBean
SqlSessionFactoryBean 实现了 Spring 的 FactoryBean 接口。 这意味着由 Spring 最终创建的 bean 并不是 SqlSessionFactoryBean 本身,而是工厂类(SqlSessionFactoryBean)的 getObject() 方法的返回结果。
这种情况下,Spring 将会在应用启动时为你创建 SqlSessionFactory,并使用 sqlSessionFactory 这个名字存储起来。
FactoryBean定义了三个方法,其源码如下:
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
// 获取泛型T的实例。用来创建Bean。当IoC容器通过getBean方法来创建FactoryBean的实例时实际获取的不是FactoryBean 本身,而是具体创建的T泛型实例。
@Nullable
T getObject() throws Exception;
// 返回FactoryBean创建的bean类型。
@Nullable
Class<?> getObjectType();
// 返回由FactoryBean创建的bean实例的作用域是singleton还是prototype。
default boolean isSingleton() {
return true;
}
}
在使用Spring声明一个Bean后,比如下面声明了一个名为animal的Bean,那么Spring通过反射机制利用bean的class属性指定实现类来实例化bean ,然后存放在IOC中。
<!--注入属性时还可以使用 p 名称空间注入,可以简化基于 xml 配置方式-->
<bean id="animal" class="org.pearl.spring.demo.pojo.Animal" p:age="18" p:name="使用P注入"/>
如果我们相对这个Bean进行属性配置,或者需要增强某些功能,采用以上的方式就比较麻烦了,这个时候我们可以声明当前类为FactoryBean的泛型,对这个Bean对象进行属性设置功能增强,再在getObject方法中获取这个Bean注入到IOC中。
2. InitializingBean
InitializingBean从字面上理解是初始化Bean,该接口在容器为 bean 设置所有必要的属性后,让 bean 执行初始化工作。该InitializingBean接口指定了一个方法:
void afterPropertiesSet() throws Exception;
3. ApplicationListener
ApplicationListener是Spring事件机制的一部分,与抽象类ApplicationEvent类配合来完成ApplicationContext的事件机制。
如果容器中存在ApplicationListener的Bean,当ApplicationContext调用publishEvent方法时,对应的Bean会被触发。这一过程是典型的观察者模式的实现。
源码如下:
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
}
SqlSessionFactoryBean初始化源码分析
在简单了解了SqlSessionFactoryBean实现了三个接口后,接着来分析下,MyBatis-Spring是怎么通过SqlSessionFactoryBean注入SqlSessionFactory的。
首先是通过new的方式创建了SqlSessionFactoryBean对象,然后添加了一个数据源配置。
接着进入到getObject()方法,此时sqlSessionFactory属性为null,所以进入到afterPropertiesSet方法。
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
this.afterPropertiesSet();
}
return this.sqlSessionFactory;
}
afterPropertiesSet会校验dataSource、sqlSessionFactoryBuilder不为空,configuration及configLocation 属性是否为null。
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();
}
校验通过后,进入到buildSqlSessionFactory方法,开始构建SqlSessionFactory并返回,该方法主要是读取SqlSessionFactoryBean相关的配置,解析为Configuration对象。
最终还是调用了build方法,通过配置创建DefaultSqlSessionFactory示例。
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
最后getObject()方法,返回添加了配置的SqlSessionFactory对象,并注入到IOC中。
总结
SqlSessionFactoryBean实际还是调用的SqlSessionFactoryBuilder的bulider方法,返回了SqlSessionFactory对象并注入到IOC中。如果不通过SqlSessionFactoryBean来获取SqlSessionFactory,那么我们需要各种添加配置,代码会变得很臃肿。
而SqlSessionFactoryBean为我们设置了很多默认配置,我们只需要注入数据库连接信息,就可以了。
来源:https://yunyanchengyu.blog.csdn.net/article/details/121014892