Author 罗先生
本文是IOC系列第四篇。往期回顾:
FactoryBean是什么?
首先看懂这篇,需要先看SpringIOC-FactoryBean
SqlsessionFactoryBean
类声明:
public class SqlSessionFactoryBean
implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent>
这里我们需要的是他和SessionFactory没有继承实现关系,只是FactoryBean声明的泛型是SqlSessionFactory不声明关系也不大。。都是为了严谨)
没有SqlsessionFactoryBean的Mybatis
举个例子,打开mybatis官网(https://mybatis.org/mybatis-3/getting-started.html),getstart会教你怎么搭建Mybatis环境,然后就会看到一大堆XMl配置,
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
之后就是Building SqlSessionFactory这个过程,最后会执行build方法
DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
TransactionFactory transactionFactory =
new JdbcTransactionFactory();
Environment environment =
new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(configuration);
可以发现build出来的是DefaultSqlSessionFactory对象,他是SqlSessionFactory的一个实现类,而上面的xml配置最终是为了配置Configuration对象,因为DefaultSqlSessionFactory的实例化需要它,
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
既然都贴了这么多文档上的东西,就全部贴完吧,其实下面就是应用了,上面已经把环境配置好了
try (SqlSession session = sqlSessionFactory.openSession()) {
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.mybatis.example.BlogMapper">
<select id="selectBlog" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper>
缺点:
SqlSessionFactory 的构造需要Configuration,而Configuration 需要依赖Environment ,而Environment 依赖比较多,他的构造要一个字符串,dataSource,还有一个TransactionFactory 对象,然后设置好Configuration后,还需要手动add mapper,整个流程下来稍微复杂,而如果Mybatis以后想新增别的依赖,这里的Java代码配置更是复杂度上升,所以Mybatis在整合Spring的时候,就使用了FactoyBean的方式来对外提供一种简单的关系。
有了SqlsessionFactoryBean之后
@Configuration
public class Appconfig {
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
return sqlSessionFactoryBean;
}
@Bean
public DataSource dataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setPassword("root");
driverManagerDataSource.setUsername("root");
driverManagerDataSource.setUsername("jdbc:mysql://localhost:3306/test");
driverManagerDataSource.setDriverClassName("com.mysql.jdbc.Driver");
return driverManagerDataSource;
}
}
优点:
简单了太多,可以发现只需要一个数据源 + SqlSessionFactoryBean ,
SqlSessionFactoryBean帮我们做了什么
我们在IOC应用-SqlsessionFactoryBean 说到了FactoryBean最终会往容器里注册一个getObject()返回的对象,如下:
@Override
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
afterPropertiesSet();
}
return this.sqlSessionFactory;
}
public void afterPropertiesSet() throws Exception {
notNull(dataSource, "Property 'dataSource' is required");
notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
"Property 'configuration' and 'configLocation' can not specified with together");
this.sqlSessionFactory = buildSqlSessionFactory();
}
protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
... //上面都不用看
targetConfiguration.setEnvironment(new Environment(this.environment,
this.transactionFactory == null ? new SpringManagedTransactionFactory() : this.transactionFactory,
this.dataSource));
return this.sqlSessionFactoryBuilder.build(targetConfiguration);
}
看到**buildSqlSessionFactory的setEnvironment()**就比较熟悉了。上面的代码还是比较容易看懂的
总结:
SqlSessionFactoryBean其实就是把内部创建SqlSessionFactory的复杂依赖关系都自己维护了,除了需要外部指定的dataSource,所以再把dataSource set进SqlSessionFactoryBean,剩下的SqlSessionFactoryBean会自己解决,最后在getObject()方法中返回的就是一个初始化好的SqlSessionFactory 对象到容器当中。