Mybatis和Spring的整合原理
上一篇提到了和Spring整合後,Mybatis的BatchExecutor無法真正生效,本篇就好好分析分析這裡面的原因
一配置檔案
<!-- 配置sqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 例項化sqlSessionFactory時需要使用上述配置好的資料來源以及SQL對映檔案 --> <property name="dataSource" ref="dataSource" /> <!-- 自動掃描me/gacl/mapping/目錄下的所有SQL對映的xml檔案, 省掉Configuration.xml裡的手工配置 value="classpath:me/gacl/mapping/*.xml"指的是classpath(類路徑)下me.gacl.mapping包中的所有xml檔案 UserMapper.xml位於me.gacl.mapping包下,這樣UserMapper.xml就可以被自動掃描 --> <property name="configLocation" value="classpath:mybatis-config.xml"/> <property name="mapperLocations" value="classpath:me/gacl/mapping/*.xml" /> </bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 掃描me.gacl.dao這個包以及它的子包下的所有對映介面類 -->
<property name="basePackage" value="me.gacl.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>
接下來我們就好好分析這兩個類SqlSessionFactoryBean ,MapperScannerConfigurer
二SqlSessionFactoryBean
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
它是一個FactoryBean,那我們只需要關注getObject方法就好了
@Override public SqlSessionFactory getObject() throws Exception { if (this.sqlSessionFactory == null) { afterPropertiesSet(); } return this.sqlSessionFactory; }
這樣,spring容器內就有一個java bean,name是我們配的sqlSessionFactory
三MapperScannerConfigurer
它實現了介面BeanDefinitionRegistryPostProcessor 就說明它具有想beanFactory註冊BeanDefinition的能力
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { if (this.processPropertyPlaceHolders) { processPropertyPlaceHolders(); } ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); scanner.setAddToConfig(this.addToConfig); scanner.setAnnotationClass(this.annotationClass); scanner.setMarkerInterface(this.markerInterface); scanner.setSqlSessionFactory(this.sqlSessionFactory); scanner.setSqlSessionTemplate(this.sqlSessionTemplate); scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName); scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName); scanner.setResourceLoader(this.applicationContext); scanner.setBeanNameGenerator(this.nameGenerator); scanner.registerFilters(); scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)); }
因為我們只配了<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /> 所以這裡 this.sqlSessionFactory = null
basePackage =me.gacl.dao
直接跳到ClassPathMapperScanner.doScan
public Set<BeanDefinitionHolder> doScan(String... basePackages) { Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages); if (beanDefinitions.isEmpty()) { logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration."); } else { for (BeanDefinitionHolder holder : beanDefinitions) { GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition(); if (logger.isDebugEnabled()) { logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + definition.getBeanClassName() + "' mapperInterface"); } // the mapper interface is the original class of the bean // but, the actual class of the bean is MapperFactoryBean definition.getPropertyValues().add("mapperInterface", definition.getBeanClassName()); definition.setBeanClass(MapperFactoryBean.class); definition.getPropertyValues().add("addToConfig", this.addToConfig); boolean explicitFactoryUsed = false; if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) { definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName)); explicitFactoryUsed = true; } else if (this.sqlSessionFactory != null) { definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory); explicitFactoryUsed = true; }
一個BeanDefinition就這樣被完成了,並註冊到beanFactory裡。它有幾個重要的屬性
1 該Bean的class是MapperFactoryBean
2 它有屬性mapperInterface 這裡是me.gacl.dao.UserMapper
3 它有屬性sqlSessionFactory 就是在上一小節得到的sqlSessionFactory (Mybatis的原生類)
好了,到這裡後我們要分析的程式碼就是MapperFactoryBean
四MapperFactoryBean
這個類不得了,可以說不能執行Batch的原因就出在他身上
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> { private Class<T> mapperInterface; private boolean addToConfig = true;
可以看出來MapperFactoryBean 本身就一個屬性mapperInterface 表示的是 me.gacl.dao.UserMapper
主要的功能和屬性都在SqlSessionDaoSupport
而且它本身就是一個FactoryBean 還是來看