Spring整合Mybatis原理分析
1、如何将Mapper的代理对象注册为Bean?
配置MapperScannerConfigurer,使用BeanDefinitionRegistryPostProcessor扩展机制将Mapper接口封装为
beanClass为MapperFactoryBean的BeanDefinition。
BeanFactoryPostProcessor
|--BeanDefinitionRegistryPostProcessor
|--MapperScannerConfigurer
ClassPathScanningCandidateComponentProvider
|--ClassPathBeanDefinitionScanner
|--ClassPathMapperScanner
ClassPathBeanDefinitionScanner+TypeFilter // TypeFilter用于过滤哪些类需要注册为BeanDefinition
ClassPathBeanDefinitionScanner#scan
ClassPathMapperScanner#doScan
ClassPathBeanDefinitionScanner#doScan
扫描指定包下的mapper,封装为BeanDefinition
将BeanDefinition封装为BeanDefinitionHolder,并将BeanDefinition注册到BeanDefinitionRegistry
ClassPathBeanDefinitionScanner#processBeanDefinitions修改BeanDefinition
设置bean构造方法参数为原beanClass(MapperFactoryBean.mapperInterface)
重新设置beanClass为MapperFactoryBean
不显式使用SqlSessionFactory则设置AutowireMode为AUTOWIRE_BY_TYPE
设置懒加载模式为false
2、如何构建SqlSessionFactory,并将其放入Spring容器中?
配置SqlSessionFactoryBean,使用扩展点InitializingBean,在属性设置完毕后构建SqlSessionFactory。
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>,
InitializingBean, ApplicationListener<ApplicationEvent> {}
SqlSessionFactory#afterPropertiesSet
SqlSessionFactory#buildSqlSessionFactory
3、MapperFactoryBean中SqlSessionTemplate是如何被注入的?
通过按类型自动注入的方式注入SqlSessionFactory,并创建SqlSessionTemplate。
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T>
public abstract class SqlSessionDaoSupport extends DaoSupport
public abstract class DaoSupport implements InitializingBean
SqlSessionDaoSupport#setSqlSessionFactory
SqlSessionDaoSupport#createSqlSessionTemplate
SqlSessionTemplate的作用?
public class SqlSessionTemplate implements SqlSession, DisposableBean {
private final SqlSessionFactory sqlSessionFactory; // 全局唯一的SqlSessionFactory
private final SqlSession sqlSessionProxy; // JDK动态代理的SqlSession。
}
SqlSessionTemplate是由Spring管理的线程安全的SqlSession。可以自动提交事务、回滚事务、关闭资源。
一个MapperFactoryBean对应一个SqlSessionTemplate;
一个SqlSessionTemplate对应一个SqlSession(sqlSessionProxy)。
SqlSessionInterceptor是SqlSession代理对象的
4、Mapper如何使用上SqlSessionTemplate?
通过SqlSessionTemplate获取Mapper生成的Mapper代理对象的MapperProxy持有了SqlSessionTemplate。
当执行Mapper的方法时由SqlSessionTemplate进行执行,SqlSessionTemplate委派给SqlSessionProxy执行。
MapperFactoryBean#getObject
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
5、SqlSessionTemplate如何确保SqlSession是线程安全的?
SqlSessionTemplate#SqlSessionInterceptor#invoke方法详解
1> 获取SqlSession
先从事务同步管理器TransactionSynchronizationManager中获取SqlSessionHolder,
如果SqlSessionHolder存在且处于事务中,则返回当前事务中的SqlSession;
否则创建一个新的SqlSession,并注册一个新的SqlSession。
若事务同步器处于活跃状态且事务工厂是Spring管理的事务工厂,则创建一个资源持有者(SqlSessionHolder),
并使用事务同步管理器绑定资源(SqlSessionFactory与SqlSessionHolder进行绑定)。
使用事务同步管理器注册事务同步器(SqlSessionSynchronization)
设置SqlSessionHolder为事务同步状态。
2> 执行SqlSession被代理的方法并返回相应的结果。
3> SqlSession是事务性质的,则提交事务。
4> 如果发生异常则先关闭SqlSession,后取出异常并抛出。
5> 最后检查如果SqlSession不为空,则关闭SqlSession。
6、使用@MapperScan注解将Mapper的代理对象注册为Bean
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {}
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {}
使用@Import+ImportBeanDefinitionRegistrar扩展机制往BeanDefinitionRegistry中注册
MapperScannerConfigurer类的Bean的BeanDefinition,再由MapperScannerConfigurer将Mapper接口封装为
beanClass为MapperFactoryBean的BeanDefinition。
MapperFactoryBean中两个属性(sqlSessionFactory/sqlSessionTemplate)说明
取决于MapperScannerConfigurer的配置
情况1:sqlSessionFactory与sqlSessionTemplate被同时指定时,sqlSessionFactory被忽略,并不使用AUTOWIRE_BY_TYPE的属性装配模式。
情况2:只指定了sqlSessionFactory,使用AUTOWIRE_BY_TYPE的属性装配模式,为每个MapperFactoryBean都创建一个sqlSessionTemplate。
情况3:只指定了sqlSessionTemplate,不使用AUTOWIRE_BY_TYPE的属性装配模式,每个MapperFactoryBean都共享同一个sqlSessionTemplate。
SpringBoot整合Mybatis原理分析
自动装配包 mybatis-spring-boot-autoconfigure-x.y.z.jar
自动装配类MybatisAutoConfiguration,提供SqlSessionFactory+SqlSessionTemplate
处理@Mapper注解的Mapper类
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
@MapperScan(basePackages = {"stu.ssmshop.dao"}, sqlSessionTemplateRef = "sqlSessionTemplate")
@SpringBootApplication
public class SsmShopBootApplication {
}
评论10