;testOnBorrow" value="false" />
<property name="testWhileIdle" value="true" />
<property name="validationQuery" value="select 1 from dual" />
<property name="filters" value="stat" />
</bean>
(5)创建sqlSessionFactory
<bean id="sqlSessionFactoryForB" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="mapperLocations" value="classpath*:com/**/mapper/*Mapper*.xml" />
<property name="dataSource" ref="dataSourceForB" />
<property name="typeAliasesPackage" value="com.zlx.***.dal" />
</bean>
(6)配置扫描器,扫描指定路径的mapper生成数据库操作代理类
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="annotationClass" value="javax.annotation.Resource"></property>
<property name="basePackage" value="com.zlx.***.dal.***.mapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactoryForB" />
</bean>
- (1)(2)(3)是一组配置, (4)(5)(6)是一组配置,配置指定的数据源到对应的包下扫描配置文件生成数据库操作代理类。
- (1)(4)分别创建了两个数据源,(2)(5)根据对应的数据源创建SqlSession工厂,(3)(6)配置mybaits扫描器,根据对应的SqlSession工厂和包路径生成代理后的数据库操作类。
2.1 原理简单介绍
2.1.1 SqlSessionFactory原理
(2)(5)作用是根据配置创建一个SqlSessionFactory,看下SqlSessionFactoryBean的代码知道它实现了FactoryBean和InitializingBean类,由于实现了InitializingBean,所以自然它的afterPropertiesSet方法,由于实现了FactoryBean类,所以自然会有getObject方法。下面看下时序图:
从时序图可知,SqlSessionFactoryBean类主要是通过属性配置创建SqlSessionFactory实例,具体是解析配置中所有的mapper文件放到configuration,然后作为构造函数参数实例化一个DefaultSqlSessionFactory作为SqlSessionFactory。
2.1.2 MapperScannerConfigurer原理
扫描指定路径的mapper生成数据库操作代理类
MapperScannerConfigurer 实现了 BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware接口,所以会重写一下方法:
//在bean注册到ioc后创建实例前修改bean定义和新增bean注册,这个是在context的refresh方法调用
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
//在bean注册到ioc后创建实例前修改bean定义或者属性值
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
//set属性设置后调用
void afterPropertiesSet() throws Exception;
//获取IOC容器上下文,在context的prepareBeanFactory中调用
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
//获取bean在ioc容器中名字,在context的prepareBeanFactory中调用
void setBeanName(String name);
先上个扫描mapper生成代理类并注册到ioc时序图:
首先MapperScannerConfigurer实现的afterPropertiesSet方法用来确保属性basePackage不为空
public void afterPropertiesSet() throws Exception {
notNull(this.basePackage, "Property 'basePackage' is required");
}
postProcessBeanFactory里面啥都没做,setBeanName获取了bean的名字,setApplicationContext里面获取了ioc上下文。下面看重要的方法postProcessBeanDefinitionRegistry,由于mybais是运行时候才通过解析mapper文件生成代理类注入到ioc,所以postProcessBeanDefinitionRegistry正好可以干这个事情。
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
if (this.processPropertyPlaceHolders) {
processPropertyPlaceHolders();
}
//构造一个C