一 dao接口扫描
1.1 注解MapperScan
-
@Import({MapperScannerRegistrar.class})
注解MapperScan -
ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()
中对@Import注解进行处理。 - 调用MapperScannerRegistrar实现接口
ImportBeanDefinitionRegistrar
的方法registerBeanDefinitions
- 解析注解参数
值 | 说明 |
---|---|
value | 扫描目标包 |
basePackages | 扫描目标包 |
basePackageClasses | 扫描目标包 |
annotationClass | 只扫描目标包里有该注解的类 |
markerInterface | 只扫描目标包里父类接口为该接口的 |
sqlSessionTemplateRef | 工厂类引用 |
sqlSessionFactoryRef | 工厂类引用 |
- 初始化
ClassPathMapperScanner
,开始包扫描scanner.doScan()
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
if(this.resourceLoader != null) {
scanner.setResourceLoader(this.resourceLoader);
}
Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
if(!Annotation.class.equals(annotationClass)) {
scanner.setAnnotationClass(annotationClass);
}
Class<?> markerInterface = annoAttrs.getClass("markerInterface");
if(!Class.class.equals(markerInterface)) {
scanner.setMarkerInterface(markerInterface);
}
Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
if(!BeanNameGenerator.class.equals(generatorClass)) {
scanner.setBeanNameGenerator((BeanNameGenerator)BeanUtils.instantiateClass(generatorClass));
}
scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));
List<String> basePackages = new ArrayList();
String[] arr$ = annoAttrs.getStringArray("value");
int len$ = arr$.length;
int i$;
String pkg;
for(i$ = 0; i$ < len$; ++i$) {
pkg = arr$[i$];
if(StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
arr$ = annoAttrs.getStringArray("basePackages");
len$ = arr$.length;
for(i$ = 0; i$ < len$; ++i$) {
pkg = arr$[i$];
if(StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
Class[] arr$ = annoAttrs.getClassArray("basePackageClasses");
len$ = arr$.length;
for(i$ = 0; i$ < len$; ++i$) {
Class<?> clazz = arr$[i$];
basePackages.add(ClassUtils.getPackageName(clazz));
}
scanner.registerFilters();
scanner.doScan(StringUtils.toStringArray(basePackages));
}
1.2 xml配置
- scan配置扫描的相关参数,初始化
ClassPathMapperScanner
,调用scanner.doScan()
进行包扫描
1.3 MapperScannerConfigurer
- 初始化
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
- 调用扫描函数
scanner.scan
-
ClassPathBeanDefinitionScanner.doScan()
扫描包路径,获取接口类的Set<BeanDefinitionHolder>
-
ClassPathMapperScanner.doScan()
把扫描到的接口类BeanDefinitionHolder修改为mybatis中使用的MapperFactoryBean.class
的BeanDefinitionHolder
1.4 ClassPathMapperScanner
- 设置类型
definition.setBeanClass(MapperFactoryBean.class);
- 设置PropertyValues,用于注入mapperInterface接口类参数
definition.getPropertyValues().add("mapperInterface", definition.getBeanClassName());
-
addToConfig
属性注入,接口表示需要添加到mybatis配置管理中 - 有sqlsession工厂配置,则设置PropertyValues注入;无工厂属性则设置为自动按类型注入。
- 返回接口对应的beandefinition
1.5 MapperFactoryBean
- 初始化时,通过
InitializingBean
接口方法afterPropertiesSet
把dao接口添加到mybatis的配置中,格式是Map<接口,MapperProxyFactory> - 这是一个工厂bean,用户从spring获取到的对应dao接口的bean对象,实际获取到的是接口的MapperProxyFactory。
public T getObject() throws Exception {
return this.getSqlSession().getMapper(this.mapperInterface);
}
- MapperProxyFactory是一个代理工厂,创建MapperProxy,代理dao接口的实际sql实现。即mybatis从sql.xml中解析出的sql语句
二 事务管理
2.1 事务管理工厂类
- SpringManagedTransactionFactory
2.2 事务管理类
- SpringManagedTransaction
-
autoCommit
纪录是否自动提交 -
isConnectionTransactional
纪录是否事务性数据库连接
2.2.1 获取sqlconnection接口
this.connection = DataSourceUtils.getConnection(this.dataSource);
-
Connection con = dataSource.getConnection();
从数据库连接池获取数据库连接,非事务直接返回。事务则封装到ConnectionHolder中。 -
TransactionSynchronizationManager
使用线程变量ThreadLocal<Map<Object, ConnectionHolder>> resources
存储事务型数据库连接。
@Transactional注解的spring事务代理入口,调用DataSourceTransactionManager
接口在TransactionSynchronizationManager存储线程共用的事务ConnectionHolder。 -
TransactionSynchronizationManager
使用线程变量ThreadLocal<Set<TransactionSynchronization>> synchronizations
表示是否处于spring事务管理中
2.3 事务关系图
事务关系图.png三 sqlSession
3.1 SqlSessionTemplate
3.1.1 使用场景
- MapperFactoryBean父类SqlSessionDaoSupport自动注入SqlSessionFactory。实际注入
SqlSessionTemplate(sqlSessionFactory)
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
if(!this.externalSqlSession) {
this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
}
}
3.1.2 内部属性
- PersistenceExceptionTranslator异常转换器,转换mybatis的PersistenceException异常为spring的DataAccessException异常
- ExecutorType表示sql执行时创建的执行器类型
- SqlSessionFactory工厂类创建sql执行器DefaultSqlSession
-
SqlSession sqlSessionProxy;
代理工厂类创建的DefaultSqlSession
3.1.3 代理处理函数SqlSessionInterceptor
- 获取线程变量SqlSessionHolder,事务型则线程内共用。
SqlSessionHolder holder = (SqlSessionHolder)TransactionSynchronizationManager.getResource(sessionFactory)
- 事务调用,则保存SqlSessionHolder到TransactionSynchronizationManager的线程变量中,以sessionFactory为key,用于线程内共享。
-
Object result = method.invoke(sqlSession, args);
sql函数调用 - spring管理的事务,则由spring提交,否则mybatis提交。
if(!SqlSessionUtils.isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
sqlSession.commit(true);
}
3.2 SqlSessionFactoryBean
-
InitializingBean.afterPropertiesSet()
创建sqlSessionFactory - xml配置文件解析
xmlConfigBuilder.getConfiguration()
- xml映射器文件解析
xmlMapperBuilder.parse()
- 别名配置,类型处理器配置,插件配置
网友评论