- 首先,从一个简单案例说起
- 从@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
@Servicepublic class UserService {@Autowiredprivate UserDao userDao;@Transactionalpublic void insertUser(){userDao.insert();//otherDao.other();xxxSystem.out.println("插入完成...");int i = 10/0;}}
UserDao.java
@Repositorypublic class UserDao {@Autowiredprivate 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")@Configurationpublic class TxConfig {//数据源@Beanpublic 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;}@Beanpublic JdbcTemplate jdbcTemplate() throws Exception{JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());return jdbcTemplate;}@Beanpublic 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 的源码如下。
@Overrideprotected 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);// 往容器中添加InfrastructureAdvisorAutoProxyCreatorregisterOrEscalateApcAsRequired(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 方法进行的注册
@Nullableprivate 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,事务为1int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());int requiredPriority = findPriorityForClass(cls);// 判断,将优先级高的后置处理器,放入容器中。//(假设一开始是事务,后来是AOP。currentPriority=0,requiredPriority=2),这判断成立,把他换成AOP的// (如果一开始是AOP,后来是事务。currentPriority=2,requiredPriority=0,这个判断不成立,容器中还是AOP)// 总结,将优先级高的后置处理器放入容器中,即如果同时存在事务和AOP,最终存在的是AOPif (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);}
