SqlSessionTemplate使用SqlSessionFactoryBean实例化之谜(以及xml配置信息迁移到java的方法)

it2026-02-13  7

最近在学习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……

最新回复(0)