SqlSessionTemplate使用SqlSessionFactoryBean实例化之谜(以及xml配置信息迁移到java的方法)
最近在学习mybatis源码时,发现了一个问题。
首先,在xml配置文件中配置了SqlSessionTemplate与SqlSessionFactoryBean。
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:${mybatis.config}"/>
<property name="mapperLocations" value="classpath*:mybatis/mapper.xml"/>
</bean>
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg>
<ref bean="sqlSessionFactory" />
</constructor-arg>
</bean>
看起来,SqlSessionTemplate是使用SqlSessionFactoryBean实例化的。
然而,查看SqlSessionTemplate的构造方法,发现:
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType());
}
SqlSessionTemplate其实是用SqlSessionFactory实例化的!
可是xml中明明写着这个bean的类型是SqlSessionFactoryBean呀,难道SqlSessionFactoryBean继承或实现了SqlSessionFactory?
继续查看源码,发现:
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
......
}
总之,SqlSessionFactoryBean并没有继承或实现了SqlSessionFactory。
这样就奇怪了,类型不匹配的话,SqlSessionTemplate到底是怎么实例化的?
后来,通过百度发现:
SqlSessionFactoryBean 实现了 Spring 的 FactoryBean 接口,
就说明了由 Spring 最终创建的 bean 不是 SqlSessionFactoryBean 本身,
而是工厂类的 getObject() 返回的方法的结果。
这种情况下, Spring 将会在应用启动时为你创建 SqlSessionFactory 对象,然后将它以 SqlSessionFactory 为名来存储。
好吧,这波操作666,本人完全没想到。
本人猜测,可能是这样实现的(正好举一个xml迁移进java的例子):
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
import javax.sql.DataSource;
@Configuration
public class MybatisConfig {
//从spring容器中获取配置数据源的其它bean对象
@Resource
private DataSource dataSource;
//从spring容器中获取处理好的对象,对应:
//classpath:${mybatis.config}
@Resource
private org.springframework.core.io.Resource configLocation;
//从spring容器中获取处理好的对象,对应:
//classpath*:mybatis/mapper.xml
@Resource
private org.springframework.core.io.Resource[] mapperLocations;
@Bean(name="sqlSessionFactory")
public SqlSessionFactory sqlSessionFactoryBeanTosqlSessionFactory() throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setConfigLocation(configLocation);
sqlSessionFactoryBean.setMapperLocations(mapperLocations);
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBean.getObject();
//虽然new了SqlSessionFactoryBean,但是返回的是SqlSessionFactory
return sqlSessionFactory;
}
}
你以为xml中配了class,获得的对象就一定是class指定的对象吗?
你以为是SqlSessionFactoryBean,其实是我SqlSessionFactory哒!
不得不说,源码这波操作是真的6……