- 首先,从一个简单案例说起
- 从@EnableTransactionManagement 开始说起
- @EnableTransactionManagement 通过@Import导入了一个组件
- 所以,紧接着看 TransactionManagementConfigurationSelector 干了什么事情
- 首先看这个类的继承图谱
- 这个类继承自 AdviceModeImportSelector, 而 AdviceModeImportSelector 又实现了ImportSelector 接口
- 在 selectImports() 中就会往容器添加一些组件, selectImports 的源码如下。
- 在@EnableTransactionManagement 注解上 默认的 AdviceMode 为 PROXY, 所以默认情况下,注册的组件为
- 那么,接下来,我们就好好看看,这两类又干了些什么。
- 在registerBeanDefinitions() 中,最主要的代码为下面这句,利用BeanDefinitionRegistry ,往容器中,注册一个InfrastructureAdvisorAutoProxyCreator。
- 在IOC容器启动时,将会调用后置处理器相应的方法。其中 如果后置处理器的类型是 InstantiationAwareBeanPostProcessor 将会调用 postProcessBeforeInstantiation 前置方法 。 postProcessAfterInitialization 后置方法( 和 AOP的原理一毛一样)
- 再看 ProxyTransactionManagementConfiguration
- 上述的事务提交,以及事务回滚,都是通过调用TransactionManager进行事务管理
- 在将TransactionInterceptor添加到容器中时,通过下述方法,将PlatformTransactionManager 绑定到了拦截器中,而这个事务管理器是从IOC容器中获取的,所以需要在最开始的配置类中,添加一个 PlatformTransactionManager
- 附录
首先,从一个简单案例说起
UserService.java
@Service
public class UserService {
@Autowired
private UserDao userDao;
@Transactional
public void insertUser(){
userDao.insert();
//otherDao.other();xxx
System.out.println("插入完成...");
int i = 10/0;
}
}
UserDao.java
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void insert(){
String sql = "INSERT INTO `tbl_user`(username,age) VALUES(?,?)";
String username = UUID.randomUUID().toString().substring(0, 5);
jdbcTemplate.update(sql, username,19);
}
}
TxConfig.java (注入一个数据库相关的资源,以及事务管理器)
@EnableTransactionManagement
@ComponentScan("cn.spectrumrpc.tx")
@Configuration
public class TxConfig {
//数据源
@Bean
public DataSource dataSource() throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("123456");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate() throws Exception{
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
return jdbcTemplate;
}
@Bean
public PlatformTransactionManager transactionManager() throws Exception{
return new DataSourceTransactionManager(dataSource());
}
}
从@EnableTransactionManagement 开始说起
@EnableTransactionManagement 通过@Import导入了一个组件
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
}
所以,紧接着看 TransactionManagementConfigurationSelector 干了什么事情
首先看这个类的继承图谱
这个类继承自 AdviceModeImportSelector, 而 AdviceModeImportSelector 又实现了ImportSelector 接口
在 selectImports() 中就会往容器添加一些组件, selectImports 的源码如下。
@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;
}
}
在@EnableTransactionManagement 注解上 默认的 AdviceMode 为 PROXY, 所以默认情况下,注册的组件为
- AutoProxyRegistrar
ProxyTransactionManagementConfiguration
AdviceMode mode() default AdviceMode.PROXY;
那么,接下来,我们就好好看看,这两类又干了些什么。
首先先看 AutoProxyRegistrar,这个类继承自 ImportBeanDefinitionRegistrar,又可以往容器中加一些组件,所以,转向registerBeanDefinitions() 方法。
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar
在registerBeanDefinitions() 中,最主要的代码为下面这句,利用BeanDefinitionRegistry ,往容器中,注册一个InfrastructureAdvisorAutoProxyCreator。
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
// 往容器中添加InfrastructureAdvisorAutoProxyCreator
registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source)
看 InfrastructureAdvisorAutoProxyCreator 的继承图谱,发现其继承了 AOP 的顶级父类 AbstractAutoProxyCreator
在IOC容器启动时,将会调用后置处理器相应的方法。其中 如果后置处理器的类型是 InstantiationAwareBeanPostProcessor 将会调用 postProcessBeforeInstantiation 前置方法 。 postProcessAfterInitialization 后置方法( 和 AOP的原理一毛一样)
再看 ProxyTransactionManagementConfiguration
- BeanFactoryTransactionAttributeSourceAdvisor 注入一个切面,用来增强目标方法
- TransactionInterceptor 目标方法的拦截器,在目标方法执行时,将会调用这个拦截器的invoke方法
所以,我们就来看看TransactionInterceptor#invoke
invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
// -> 开启事务,如果需要
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
// -> 执行目标方法
retVal = invocation.proceedWithInvocation();
// -> catch 如果发生异常,进行回滚
completeTransactionAfterThrowing(txInfo, ex);
// -> 啥事没有,提交事务
commitTransactionAfterReturning(txInfo);
上述的事务提交,以及事务回滚,都是通过调用TransactionManager进行事务管理
public PlatformTransactionManager getTransactionManager() {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
return this.transactionManager;
}
在将TransactionInterceptor添加到容器中时,通过下述方法,将PlatformTransactionManager 绑定到了拦截器中,而这个事务管理器是从IOC容器中获取的,所以需要在最开始的配置类中,添加一个 PlatformTransactionManager
interceptor.setTransactionManager(this.txManager)
附录
当我们同时使用@EnableTransactionManagement以及@EnableAspectJAutoProxy时,都知道会导入相应的后置处理器。
在AOP中导入的后置处理器
registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
在事务中导入的后置处理器
registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source)
可以看出,都是调用 registerOrEscalateApcAsRequired 方法进行的注册
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
// 判断容器中是否有org.springframework.aop.config.internalAutoProxyCreator的Bean定义
// 第一次Enable进来时,不管是谁进来,这个判断都是不存在,就会走到下面去
// 当第二个Enable进来时,这个判断就成立了
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
// 就会从容器中拿到这个Bean定义
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
// 判断当前容器中的这个Bean的class是否和我要注册的Bean的class相同
// 因为是事务和aop,所以class肯定不相同
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
// 就会进入到这边来,寻找这个class对应的优先级,寻找优先级详见下一步
// AOP为2,事务为1
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
// 判断,将优先级高的后置处理器,放入容器中。
//(假设一开始是事务,后来是AOP。currentPriority=0,requiredPriority=2),这判断成立,把他换成AOP的
// (如果一开始是AOP,后来是事务。currentPriority=2,requiredPriority=0,这个判断不成立,容器中还是AOP)
// 总结,将优先级高的后置处理器放入容器中,即如果同时存在事务和AOP,最终存在的是AOP
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
// 第一次进来,创建这个Bean定义,将他注册到容器中
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;
}
寻找优先级代码
通过一个 APC_PRIORITY_LIST 来进行优先级的判断,或者到在这个集合中的下标,当作其优先级
private static int findPriorityForClass(@Nullable String className) {
for (int i = 0; i < APC_PRIORITY_LIST.size(); i++) {
Class<?> clazz = APC_PRIORITY_LIST.get(i);
if (clazz.getName().equals(className)) {
return i;
}
}
throw new IllegalArgumentException(
"Class name [" + className + "] is not a known auto-proxy creator class");
}
而 APC_PRIORITY_LIST这个集合,在静态代码块中,进行了初始化赋值
从初始化出来的集合中可以看出,事务导入的后置处理器(_InfrastructureAdvisorAutoProxyCreator)获取出来的为0,AOP导入的后置处理器(AnnotationAwareAspectJAutoProxyCreator)获取出来的为2_
static {
// Set up the escalation list...
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}