一、如何整合进Spring中的
默认大家对Spring都比较了解了,这里只说结果。都知道接口是不能被实例化的,那么接口是如何成为Bean的呢?
1.1 如何知道哪些是Mybatis的接口呢?
@MapperScan Spring中在配置类上加上这个注解。根据源码能看到还导入了 MapperScannerRegistrar
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {}
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {}
MapperScannerRegistrar 会在配置类解析时候拿到 MapperScan 注解信息,并解析里面的参数。生成一个 MapperScannerConfigurer 信息。
从源码中能看到Mybatis的很多配置信息,都会被注入到 MapperScannerConfigurer 中。
public class MapperScannerConfigurer
implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {}
实现自BeanDefinitionRegistryPostProcessor会前置,拿到MapperScan中的basePackage,最终通过 ClassPathMapperScanner 扫描并添加到
BeanDefinitionRegistry 中。
到这里这种方式就能知道哪些是Mybatis中的Mapper接口了。
还有第二种方式当发现Spring容器中没有 MapperScannerConfigurer 。会自动注入一个
会直接指定哪些类被Mapper修饰,就将他生成Bean。
好了,到这里就知道如何来确定那些接口是要生成Mybatis接口的了。下面看下个问题。
1.2 Mapper接口是如何变成Spring Bean的?
接口是不能被实例化的,但是在Spring中如何想让接口实例化就可以使用FactoryBean + 动态代理的方式,实现接口类的实例化
MapperFactoryBean
二、Spring在哪里声明的SqlSession的实现逻辑?
通过Mybatis的学习知道SqlSession一共有2个包装类。SqlSessionManager和SqlSessionTemplate。那么SqlSession是在哪里指定用哪个的呢?
答案就在 MapperFactoryBean
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
private SqlSessionTemplate sqlSessionTemplate;
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) {
this.sqlSessionTemplate = createSqlSessionTemplate(sqlSessionFactory);
}
}
@SuppressWarnings("WeakerAccess")
protected SqlSessionTemplate createSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
三、Spring中声明式事务的实现方式是怎样的
看了Mybatis中事务这一章节,知道如果使用了SqlSessionTemplate,那么事务的权限就外包给了Spring。那么Spring中事务怎么处理的呢?
终于进入正题了。Spring中提供两种事务的能力。
声明式事务
编程式事务
3.1 声明式事务
使用 Transactional 修饰方法,其主要实现是使用切面实现。
TransactionAspectSupport#invokeWithinTransaction 。拦截方法。获取事务管理器。
这里我们先来思考下,通过前面的学习知道事务的最底层实现是jdbc驱动来实现的。
那么切面中要想实现,就必须保证切面中的线程执行的数据库操作,一定是同一个 SqlSession 这样才能在方法正常执行时候做commit,异常时候做rollback操作。
那我们看下他是如何保证切面中的数据库操作一定是同一个SqlSession的吧。这部分逻辑就在 SqlSessionTemplate 中。
获取当前线程是否已经有SqlSession了,如果有就直接使用,这样就保证在切面中的事务用的是同一个事务了。
3.2 编程式事务
TransactionTemplate#execute
编程是事务需要实现者自己来管理事务的,Spring提供的扩展接