- 事务管理器的接口是 PlatformTransactionManager ,其中定义了三个接口的方法如下:
- TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException :获取事务,如果当前没有事务,那么就根据传播级别创建一个事务。
- TransactionDefinition :其中定义了事务的传播属性,比如默认的传播属性(当前没有事务就开启事务)等。
- void commit(TransactionStatus status) throws TransactionException; :提交事务
- TransactionStatus :其中定义了一些事务的状态和查询、判断事务状态的方法
- void rollback(TransactionStatus status) throws TransactionException; :回滚事务
- PlatformTransactionManager 的实现类有很多,比如结合JDBC操作的 DataSourceTransactionManager 、配置JTA、Hibernate的事务管理器。
注入事务管理器【JDBC】
- 注入 PlatformTransactionManager ,步骤如下:
- 注入数据源,这里我们使用的是结合JDBC,因此需要注入对应的事务管理器 DataSourceTransactionManager
//注入数据源,这里使用的是阿里的Druid,这里只是简单的配置
@Bean
public DruidDataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUsername("******");
dataSource.setPassword("*****");
dataSource.setUrl("******");
dataSource.setInitialSize(10);
dataSource.setMaxActive(20);
dataSource.setMaxIdle(100000);
return dataSource;
}
//注入事务管理器
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource);
return dataSourceTransactionManager;
}
- 开启事务,使用 @EnableTransactionManagement
@Configuration
@ComponentScan(basePackages = {"cn.tedu.demo.*"})
@EnableTransactionManagement
public class MainConfig{}
源码解析事务
必知的知识和类
PlatformTransactionManager
- 事务管理器的接口,其中定义一些事务的方法,有提交,回滚,获取事务的方法。
- 实现类如下:DataSourceTransactionManager JtaTransactionManager
TransactionDefinition
- 该接口主要定义了事务的一些属性,比如事务的传播行为,隔离级别等数据。
@EnableTransactionManagement
- 此注解的源码如下,其实真正起作用的就是 @Import(TransactionManagementConfigurationSelector.class) ,使用 @Import 这个注解向容器中注入了其他的Bean,详情请看我的 Spring注解版开发,其中有@Import的使用
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
TransactionManagementConfigurationSelector
- 这个实现了 ImportSelector ,结合@Import注解使用,是@Import注解的注入Bean的其中一种方式,有一个必须重载的方法,如下:此方法返回的 BeanName 的数组的全部Bean将会被注入到容器中
String[] selectImports(AnnotationMetadata importingClassMetadata);
- TransactionManagementConfigurationSelector对上面的这个方法重写了,如下:
- 主要流程就是根据 @EnableTransactionManagement 中mode属性返回对应的BeanName,如果值是 PROXY 【默认】,那么就会注入 AutoProxyRegistrar 、 ProxyTransactionManagementConfiguration 这两个Bean,那么这个方法的作用就是如此,因此我们需要看看注入的两个Bean到底是什么作用?
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass(){
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
AutoProxyRegistrar
- 该类实现了 ImportBeanDefinitionRegistrar ,主要的作用就是根据 @EnableTransactionManagement 属性中的 mode 和 proxyTargetClass ,注入对应的 AutoProxyCreator 【APC】,代码如下:
//importingClassMetadata:其中封装了配置类的所有注解
//registry:用于注入BeanDefintion
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry){
//标记
boolean candidateFound = false;
//获取所有的注解类型
Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
//遍历注解
for (String annoType : annoTypes) {
//获取指定注解的全部属性的值
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
if (candidate == null) {
continue;
}
//获取对应的mode和proxyTargetClass属性的值
Object mode = candidate.get("mode");
Object proxyTargetClass = candidate.get("proxyTargetClass");
//如果这些值都存在,那么可以判定配置类上标注了`@EnableTransactionManagement`这个注解
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
Boolean.class == proxyTargetClass.getClass()) {
//标记设置为true
candidateFound = true;
//根据mode的值,注入不同的APC
if (mode == AdviceMode.PROXY) {
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
if (!candidateFound && logger.isInfoEnabled()) {
String name = getClass().getSimpleName();
logger.info(String.format("%s was imported but no annotations were found " +
"having both 'mode' and 'proxyTargetClass' attributes of type " +
"AdviceMode and boolean respectively. This means that auto proxy " +
"creator registration and configuration may not have occurred as " +
"intended, and components may not be proxied as expected. Check to " +
"ensure that %s has been @Import'ed on the same class where these " +
"annotations are declared; otherwise remove the import of %s " +
"altogether.", name, name, name));
}
}
- 其中核心的代码就是注入不同的APC的代码,如下:AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
- 实际作用的源码如下:实际作用的源码如下:
//cls是InfrastructureAdvisorAutoProxyCreator.class,APC的一种实现类
//注入的BeanName是org.springframework.aop.config.internalAutoProxyCreator
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
//判断对应的APC是否已经注入了
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
//没有注入,直接使用RootBeanDefinition注入,BeanName是org.springframework.aop.config.internalAutoProxyCreator
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); :强制使用子类代理【cglib代理】,实际作用的源码如下:
- 实际的作用就是设置了 proxyTargetClass 为true
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry){
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
}
}
总结
- 该类是TransactionManagementSlector选择器注入的类,主要作用就是根据@EnableTranactionMangement注解中的mode和proxyTarget的值注入(AutoProxyCreator)【简称APC】,实际的APC的类型是 InfrastructureAdvisorAutoProxy