1. 案例(注解版)
- 引入依赖 build.gradle文件:
dependencies { api(project(":spring-context")) api(project(":spring-aspects")) //引入aop&切面模块 api(project(":spring-jdbc")) //引入jdbc模块 // https://mvnrepository.com/artifact/c3p0/c3p0 implementation group: 'c3p0', name: 'c3p0', version: '0.9.1.2' // https://mvnrepository.com/artifact/mysql/mysql-connector-java implementation group: 'mysql', name: 'mysql-connector-java', version: '8.0.18' // https://mvnrepository.com/artifact/org.projectlombok/lombok compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.14' } 复制代码
- 注解版配置文件
@ComponentScan("com.hsf.spring.tx") @Configuration @EnableTransactionManagement public class TxConfig { @Bean public DataSource dataSource() throws Exception { ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setUser("root"); dataSource.setPassword("hsfxuebao"); dataSource.setDriverClass("com.mysql.cj.jdbc.Driver"); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/spring_tx"); return dataSource; } @Bean public JdbcTemplate jdbcTemplate() throws Exception { // Spring对@Configuration类会特殊处理,给容器中加组件的方法,多次调用都只是从容器中找组件 return new JdbcTemplate(dataSource()); } // 注册事务管理器 @Bean public PlatformTransactionManager transactionManager() throws Exception { return new DataSourceTransactionManager(dataSource()); } } 复制代码
- 实例类
@Repository public class UserDao { @Autowired private JdbcTemplate jdbcTemplate; public void insert() { String sql = "INSERT INTO user(name,age) values(?,?)"; String name = UUID.randomUUID().toString().substring(0, 5); jdbcTemplate.update(sql, name, 19); } } @Service public class UserInfoService { public void test() { System.out.println("UserInfoService.test()"); } } @Service public class UserService { @Autowired private UserDao userDao; // 不自动注入,模拟空指针异常 private UserInfoService userInfoService; @Transactional() public void insertUser() { userDao.insert(); System.out.println("插入完成"); // 模拟空指针异常 userInfoService.test(); } } 复制代码
- 测试类
public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TxConfig.class); // 事务 UserService userService = context.getBean(UserService.class); userService.insertUser(); } 复制代码
2. @EnableTransactionManagement
我们第1小节中开始事务管理很简单,使用 @EnableTransactionManagement
注解即可。那么也就说明 @EnableTransactionManagement
是我们分析的入口了。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(TransactionManagementConfigurationSelector.class) public @interface EnableTransactionManagement { boolean proxyTargetClass() default false; AdviceMode mode() default AdviceMode.PROXY; int order() default Ordered.LOWEST_PRECEDENCE; } 复制代码
很明显了 @Import(TransactionManagementConfigurationSelector.class)
指向我们去看 去看 TransactionManagementConfigurationSelector
的实现。
2.1 TransactionManagementConfigurationSelector
可以看到, TransactionManagementConfigurationSelector
间接实现了 ImportSelector
接口, ImportSelector
会根据 selectImports
返回的字符串数组(一般是类的全路径名) 通过 反射加载该类并注册到Spring容器中
。
所以我们这里必然来看一下 selectImports
方法了, ImportSelector#selectImports
的实现在其父类 AdviceModeImportSelector#selectImports
:
@Override public final String[] selectImports(AnnotationMetadata importingClassMetadata) { // 获取注解类型, 这里是 EnableTransactionManagement Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class); Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector"); // 解析出 @EnableTransactionManagement 注解的参数 AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType); if (attributes == null) { throw new IllegalArgumentException(String.format( "@%s is not present on importing class '%s' as expected", annType.getSimpleName(), importingClassMetadata.getClassName())); } // 获取mode属性。EnableTransactionManagement 默认mode = AdviceMode.PROXY AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName()); // 调用 TransactionManagementConfigurationSelector#selectImports String[] imports = selectImports(adviceMode); if (imports == null) { throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode); } return imports; } ... @Nullable protected abstract String[] selectImports(AdviceMode adviceMode); 复制代码
可以知道了 这里是将 protected abstract String[] selectImports(AdviceMode adviceMode);
返回的值返回给 Spring。这里我们看看在 TransactionManagementConfigurationSelector
中的 selectImports(AdviceMode adviceMode)
方法的实现。
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> { @Override protected String[] selectImports(AdviceMode adviceMode) { // 默认值 是 PROXY。个人猜测是通过 代理模式实现事务,如果是 ASPECTJ 则是通过 ASPECTJ的方式实现,AspectJ 需要单独引入编译 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
和 ProxyTransactionManagementConfiguration
。
AutoProxyRegistrar
: 主要是注册了InfrastructureAdvisorAutoProxyCreator
自动代理创建器。而InfrastructureAdvisorAutoProxyCreator
的逻辑基本上和 Aop 的逻辑相同ProxyTransactionManagementConfiguration
: 注册了事务实现的核心 Bean,包括BeanFactoryTransactionAttributeSourceAdvisor
、TransactionAttributeSource
、TransactionInterceptor
等
3. AutoProxyRegistrar
AutoProxyRegistrar
实现了 ImportBeanDefinitionRegistrar
接口,所以我们要去看看他的 registerBeanDefinitions
方法的实现。
AutoProxyRegistrar#registerBeanDefinitions
代码如下:
@Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { boolean candidateFound = false; // 获取 当前类上的所有注解 Set<String> annTypes = importingClassMetadata.getAnnotationTypes(); for (String annType : annTypes) { // 获取注解的所有属性 AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType); if (candidate == null) { continue; } // 获取mode、proxyTargetClass 属性 Object mode = candidate.get("mode"); Object proxyTargetClass = candidate.get("proxyTargetClass"); if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() && Boolean.class == proxyTargetClass.getClass()) { candidateFound = true; // 判断如果是 Proxy 模式,也就是默认模式,注册自动代理创建器 if (mode == AdviceMode.PROXY) { AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); // 如果需要代理目标列,则强制自动代理创建者使用类代理 if ((Boolean) proxyTargetClass) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); return; } } } } ... 省略日志打印 } 复制代码
在这里我们可以看到, registerBeanDefinitions
方法中解析了 事务注解
,并 注册了自动代理创建器
。这里自动代理创建器我们在Aop 源码中提到过,是Aop 创建的核心。
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)
这一步最主要的作用将自动代理创建器 InfrastructureAdvisorAutoProxyCreator
注册到了 Spring容器中。
经过数次跳转,我们来到了 AopConfigUtils#registerOrEscalateApcAsRequired
。其中这
public static final String AUTO_PROXY_CREATOR_BEAN_NAME = "org.springframework.aop.config.internalAutoProxyCreator"; private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3); static { // Set up the escalation list... // 事务使用 APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class); APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class); // Spring aop 使用 APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class); } .... public static BeanDefinition registerAutoProxyCreatorIfNecessary( BeanDefinitionRegistry registry, @Nullable Object source) { return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source); } ... // 这里的 cls 是 InfrastructureAdvisorAutoProxyCreator .class private static BeanDefinition registerOrEscalateApcAsRequired( Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); // 如果有注册,则判断优先级,将优先级的高的保存 // 如果已经纯在了自动代理创建器,且存在的自动代理创建器与现在的并不一致,那么需要根据优先级来判断到底要使用哪个 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) { // 改变bean所对应的className 属性 apcDefinition.setBeanClassName(cls.getName()); } } // 如果已经存在自动代理创建器,并且与将要创建的一致,那么无需再次创建 return null; } 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 集合的顺序 public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) { if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); // 设置 proxyTargetClass 属性 definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE); } } ... public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) { if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); // 设置 exposeProxy 属性 definition.getPropertyValues().add("exposeProxy", Boolean.TRUE); } } 复制代码
到这里我们基本可以断定和 Aop 的逻辑基本相同了,只不过事务默认自动注入的自动代理创建器是 InfrastructureAdvisorAutoProxyCreator
类型。
注意:
- 在AOP 中我们知道 Aop创建的自动代理创建器类型是
AnnotationAwareAspectJAutoProxyCreator
,而事务创建的类型是InfrastructureAdvisorAutoProxyCreator
。 - 这里之所以
beanName (AUTO_PROXY_CREATOR_BEAN_NAME)
和 bean的类型并不相同,是因为这个beanName 特指内部的自动代理创建器,但是自动创建代理器会对应多种不同的实现方式。比如在默认的事务中,注入的bean类型却为InfrastructureAdvisorAutoProxyCreator
,而AOP的实现却是AnnotationAwareAspectJAutoProxyCreator
。 - 关于自动代理创建器优先级的问题,我们可以看到
APC_PRIORITY_LIST
集合的顺序,下标越大,优先级越高
。因此可以得知优先级的顺序应该是InfrastructureAdvisorAutoProxyCreator < AspectJAwareAdvisorAutoProxyCreator < AnnotationAwareAspectJAutoProxyCreator
3.1 InfrastructureAdvisorAutoProxyCreator
上面我们可以知道,事务将自动代理创建器 InfrastructureAdvisorAutoProxyCreator
注册到了 Spring容器中。这里就跟Aop 基本相同了,下面我们来看看 InfrastructureAdvisorAutoProxyCreator
的内容
可以看到 InfrastructureAdvisorAutoProxyCreator
并没有实现什么逻辑,主要逻辑在其父类 AbstractAutoProxyCreator
中。我们在Aop 中提到过, AbstractAutoProxyCreator
是自动代理创建器的基础。绝大部分逻辑都是在其中实现的。(AbstractAutoProxyCreator 是AbstractAdvisorAutoProxyCreator 的父类,是 InfrastructureAdvisorAutoProxyCreator 的 "爷爷"类)。
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator { @Nullable private ConfigurableListableBeanFactory beanFactory; @Override protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) { super.initBeanFactory(beanFactory); this.beanFactory = beanFactory; } @Override // 校验bean是否合格 protected boolean isEligibleAdvisorBean(String beanName) { return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) && this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE); } } 复制代码
关于 AbstractAutoProxyCreator
的分析量十分巨大,这里不再重写分析一遍,详细内容可以去看 AOP分析文章的 AbstractAutoProxyCreator
部分。
3.2 事务中的 findCandidateAdvisors 方法
在这里,我们可以发现的是: Aop 的使用的是 AnnotationAwareAspectJAutoProxyCreator
自动代理创建器;事务使用的是 InfrastructureAdvisorAutoProxyCreator
自动代理创建器。而Aop代理创建的关键逻辑就自动代理创建器中。
我们对比后两种自动代理创建器后,惊奇的发现,其现实逻辑基本一致。最大的不同之处在于,Aop 重写了 AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
方法。而事务并没有重写这一部分。所以事务调用的实际上是 AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
。即下面一部分
protected List<Advisor> findCandidateAdvisors() { Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available"); return this.advisorRetrievalHelper.findAdvisorBeans(); } 复制代码
而Spring aop调用的则是重写后的 AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
:
@Override protected List<Advisor> findCandidateAdvisors() { // Add all the Spring advisors found according to superclass rules. List<Advisor> advisors = super.findCandidateAdvisors(); // Build Advisors for all AspectJ aspects in the bean factory. if (this.aspectJAdvisorsBuilder != null) { advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; } 复制代码
可以清楚的看到,Aop 的重写是加了 this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
方法调用,也就是动态生成 Advisor
的部分。
关于 getAdvicesAndAdvisorsForBean
的源码分析可以看 Spring5源码13-AOP源码分析(上)
到这里我们知道了 相较于 Aop 的 ,事务的 InfrastructureAdvisorAutoProxyCreator
,不仅没有添加新逻辑(关键逻辑),还砍掉了动态生成Advisor 的逻辑。
3.3 为什么事务实现不需要动态生成Advisor 部分?
个人理解是因为由于事物的切入点并不像AOP那样如此多变。
- 何为Aop的切入点多变,即Pointcut的定义规则由代码掌握,我们通过
@Pointcut
注解 可以定义一个匹配所有方法的切面,也可以定义一个匹配到指定的方法的切面,对于Spring来说,Spring无法通过一个Advisor
满足诸多Pointcut 条件,而为了满足这个条件所以需要通过代码来动态解析所有的Pointcut 来封装成一个一个的 Advisor,随后便可以通过 Advisor 来判断该方法是否满足某个 Advisor 的切入要求。 - 而对于事务来说,启用事务的方法必须要使用
@Transactional
来修饰方法(也可以修饰在类上,但这里为了方便描述直接说方法上,并且在类上使用更符合编程习惯)。也就是说对Spring来说,判断一个方法是否启用事务的依据就是该方法上是否使用了@Transactional
注解。也就是说,我们仅需要一个Advisor
,其判断条件是方法是否被@Transactional
注解修饰即可。而既然知道了Pointcut
条件,我们就可以实现编写好满足这个逻辑的 Advisor,在Spring启动时候直接将这个条件的 Advisor 注入到容器中直接使用。 - 综上,事务并不需要去动态注入
Advisor
,而Spring aop 则需要动态注入。
通过上面的分析,我们判断,事务的Advisor 已经事先注入了,然后我们回头看到 TransactionManagementConfigurationSelector
中注入的另一个类 ProxyTransactionManagementConfiguration
。在 ProxyTransactionManagementConfiguration
中果不其然发现了Advisor 的踪迹。
4. ProxyTransactionManagementConfiguration
ProxyTransactionManagementConfiguration
代码如下,并没有逻辑,就是将几个Bean注入的到容器中。不过这几个bean可都是关键bean,所以我们需要对其中的bean进行分析。
@Configuration(proxyBeanMethods = false) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration { @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor( TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) { BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor(); advisor.setTransactionAttributeSource(transactionAttributeSource); advisor.setAdvice(transactionInterceptor); if (this.enableTx != null) { advisor.setOrder(this.enableTx.<Integer>getNumber("order")); } return advisor; } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionAttributeSource transactionAttributeSource() { return new AnnotationTransactionAttributeSource(); } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) { TransactionInterceptor interceptor = new TransactionInterceptor(); interceptor.setTransactionAttributeSource(transactionAttributeSource); if (this.txManager != null) { interceptor.setTransactionManager(this.txManager); } return interceptor; } } 复制代码
BeanFactoryTransactionAttributeSourceAdvisor
: 事务的增强器,该方法是否开始事务,是否需要代理该类都在该类中判断
TransactionAttributeSource TransactionInterceptor
4.1 BeanFactoryTransactionAttributeSourceAdvisor
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor { @Nullable private TransactionAttributeSource transactionAttributeSource; private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() { @Override @Nullable protected TransactionAttributeSource getTransactionAttributeSource() { return transactionAttributeSource; } }; /** * Set the transaction attribute source which is used to find transaction * attributes. This should usually be identical to the source reference * set on the transaction interceptor itself. * @see TransactionInterceptor#setTransactionAttributeSource */ public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) { this.transactionAttributeSource = transactionAttributeSource; } /** * Set the {@link ClassFilter} to use for this pointcut. * Default is {@link ClassFilter#TRUE}. */ public void setClassFilter(ClassFilter classFilter) { this.pointcut.setClassFilter(classFilter); } @Override public Pointcut getPointcut() { return this.pointcut; } } 复制代码
这个根据上面的分析,我们可以知道这个是事务判断的核心, BeanFactoryTransactionAttributeSourceAdvisor
是 Advisor
子类,那么我们可以知道其中有两个关键属性: Pointcut
(判断是否可以作用于当前方法) 和 Advice
(作用于当前方法的具体逻辑)。
通过 Aop文章的分析我们可以知道, Advisor
判断一个方法是否匹配,是通过其 Pointcut.matchs
属性来判断的。然后我们通过上面的代码,发现其 Pointcut
的实现类是 TransactionAttributeSourcePointcut
,也就是说,一个方法是否需要使用事务,是通过 TransactionAttributeSourcePointcut#matches
方法判断的。
4.1.1. TransactionAttributeSourcePointcut
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable { protected TransactionAttributeSourcePointcut() { setClassFilter(new TransactionAttributeSourceClassFilter()); } @Override public boolean matches(Method method, Class<?> targetClass) { // 调用 TransactionAttributeSource.getTransactionAttribute方法来匹配 TransactionAttributeSource tas = getTransactionAttributeSource(); return (tas == null || tas.getTransactionAttribute(method, targetClass) != null); } ... 省略一些无关代码 /** * Obtain the underlying TransactionAttributeSource (may be {@code null}). * To be implemented by subclasses. */ @Nullable protected abstract TransactionAttributeSource getTransactionAttributeSource(); /** * {@link ClassFilter} that delegates to {@link TransactionAttributeSource#isCandidateClass} * for filtering classes whose methods are not worth searching to begin with. */ private class TransactionAttributeSourceClassFilter implements ClassFilter { @Override public boolean matches(Class<?> clazz) { // 如果是一些基础类,则返回false if (TransactionalProxy.class.isAssignableFrom(clazz) || PlatformTransactionManager.class.isAssignableFrom(clazz) || PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) { return false; } // 调用 TransactionAttributeSource.isCandidateClass 方法来匹配 TransactionAttributeSource tas = getTransactionAttributeSource(); return (tas == null || tas.isCandidateClass(clazz)); } } } 复制代码
Aop中我们总结了 Pointcut
匹配的需要满足下面两个条件:
pc.getClassFilter().matches(targetClass) pc.getMethodMatcher().matches(method, targetClass)
如下图,具体实现在 AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class<?>, boolean)
中,这里第二点不考虑,因为在这里不会为True
通过 TransactionAttributeSourcePointcut
的代码我们可以发现,上面两个条件的关键 可以转换成
- 调用
TransactionAttributeSource.isCandidateClass
方法来匹配 :TransactionAttributeSourceClassFilter#matches
中调用了该方法 - 调用
TransactionAttributeSource.getTransactionAttribute
方法来匹配
而 TransactionAttributeSource
正是我们在 ProxyTransactionManagementConfiguration
中注入的 AnnotationTransactionAttributeSource
。
4.2 AnnotationTransactionAttributeSource
经过上面的分析,我们知道了主要逻辑在 isCandidateClass
和 getTransactionAttribute
方法中,也就是一个Bean 是否需要事务代理需要通过下面两个方法的校验。因此我们下面来看看这两个方法的实现
4.2.1 AnnotationTransactionAttributeSource#isCandidateClass
isCandidateClass
主要是 判断是否是候选类
,即 当前的的注解解析器annotationParsers
是否可以解析当前类。 annotationParsers
的初始化在其构造函数中,在初始化的过程中中添加了 SpringTransactionAnnotationParser
,我们后面的事务注解解析就是通过 SpringTransactionAnnotationParser
进行的解析。
这里annotationParsers 有三种解析类型:
SpringTransactionAnnotationParser
:即我们默认的事务解析器,解析的注解是org.springframework.transaction.annotation.Transactional
JtaTransactionAnnotationParser
:解析的注解是javax.transaction.Transactional
Ejb3TransactionAnnotationParser
:解析的注解是javax.ejb.TransactionAttribute
private final Set<TransactionAnnotationParser> annotationParsers; ... public AnnotationTransactionAttributeSource() { this(true); } ... public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) { this.publicMethodsOnly = publicMethodsOnly; // 可以看到,无论什么场景 SpringTransactionAnnotationParser 都是必定存在的解析器 if (jta12Present || ejb3Present) { this.annotationParsers = new LinkedHashSet<>(4); this.annotationParsers.add(new SpringTransactionAnnotationParser()); if (jta12Present) { this.annotationParsers.add(new JtaTransactionAnnotationParser()); } if (ejb3Present) { this.annotationParsers.add(new Ejb3TransactionAnnotationParser()); } } else { this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser()); } } @Override public boolean isCandidateClass(Class<?> targetClass) { for (TransactionAnnotationParser parser : this.annotationParsers) { // 这里是SpringTransactionAnnotationParser 类型, SpringTransactionAnnotationParser#isCandidateClass 中判断了目标类是否存在 org.springframework.transaction.annotation.Transactional 注解 if (parser.isCandidateClass(targetClass)) { return true; } } return false; } 复制代码
在 SpringTransactionAnnotationParser#isCandidateClass
中判断了目标类是否存在 org.springframework.transaction.annotation.Transactional
注解,如果存在,这里会返回true,通过校验
4.2.2 AbstractFallbackTransactionAttributeSource#getTransactionAttribute
getTransactionAttribute
方法的实现在其父类 AbstractFallbackTransactionAttributeSource
中 实现的:
// 获取事务属性,如果 public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) { // 判断声明类是否是 Object if (method.getDeclaringClass() == Object.class) { return null; } // First, see if we have a cached value. // 尝试从缓冲中获取 Object cacheKey = getCacheKey(method, targetClass); TransactionAttribute cached = this.attributeCache.get(cacheKey); if (cached != null) { // Value will either be canonical value indicating there is no transaction attribute, // or an actual transaction attribute. if (cached == NULL_TRANSACTION_ATTRIBUTE) { return null; } else { return cached; } } else { // We need to work it out. // 没有缓存,则开始解析 TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass); // Put it in the cache. // 获取 if (txAttr == null) { // 放入缓存中 this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE); } else { // 获取合适的方法名称 String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass); if (txAttr instanceof DefaultTransactionAttribute) { ((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification); } if (logger.isTraceEnabled()) { logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr); } this.attributeCache.put(cacheKey, txAttr); } return txAttr; } } ... // 解析事务注解属性 protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) { // Don't allow no-public methods as required. // 如果只允许解析public 方法 && 当前方法不是 publissh if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { return null; } // The method may be on an interface, but we need attributes from the target class. // If the target class is null, the method will be unchanged. // method 代表接口中的方法,specificMethod 方法代表实现类中的方法 Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass); // First try is the method in the target class. // 寻找实现类方法的事务属性,即类方法是否有声明事务属性 TransactionAttribute txAttr = findTransactionAttribute(specificMethod); if (txAttr != null) { return txAttr; } // Second try is the transaction attribute on the target class. // 在实现类上是否有事务属性的声明 txAttr = findTransactionAttribute(specificMethod.getDeclaringClass()); if (txAttr != null && ClassUtils.isUserLevelMethod(method)) { return txAttr; } // 如果存在接口方法,则从接口方法中尝试去获取事务属性 if (specificMethod != method) { // Fallback is to look at the original method. txAttr = findTransactionAttribute(method); if (txAttr != null) { return txAttr; } // Last fallback is the class of the original method. txAttr = findTransactionAttribute(method.getDeclaringClass()); if (txAttr != null && ClassUtils.isUserLevelMethod(method)) { return txAttr; } } // 都没得到则返回没有得到 return null; } 复制代码
这里的逻辑还是很清楚的
- 从实现类方法上获取事务注解,若获取到则返回
- 从实现类上获取事务注解,若获取到则返回
- 如果存在接口方法,则从接口方法中获取事务注解,若获取到则返回
- 若仍未获取到,则返回null,认为当前方法没有被注解修饰
AnnotationTransactionAttributeSource#findTransactionAttribute(java.lang.reflect.Method)
在上面的代码中,我们注意到一个方法 findTransactionAttribute
。上面代码就是通过 findTransactionAttribute
方法来寻找事务注解属性的。而findTransactionAttribute 的实现在 AnnotationTransactionAttributeSource
中。其实现代码如下
protected TransactionAttribute findTransactionAttribute(Method method) { return determineTransactionAttribute(method); } ... protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) { for (TransactionAnnotationParser parser : this.annotationParsers) { TransactionAttribute attr = parser.parseTransactionAnnotation(element); if (attr != null) { return attr; } } return null; } 复制代码
可以看到 AnnotationTransactionAttributeSource
中获取 事务注解是通过 TransactionAnnotationParser#parseTransactionAnnotation
方法去解析的,而一开始我们就说过 annotationParsers
在构造函数中添加了 SpringTransactionAnnotationParser
。我们来看看 SpringTransactionAnnotationParser
进行了怎么样的解析。到这里,我们终于看到了事务注解的描述,这里就是解析事务注解的各种属性信息了.
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) { // 获取事务注解的属性信息 AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes( element, Transactional.class, false, false); if (attributes != null) { return parseTransactionAnnotation(attributes); } else { return null; } } .... // 解析事务注解,并返回 protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) { RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); // 解析各种属性信息 Propagation propagation = attributes.getEnum("propagation"); rbta.setPropagationBehavior(propagation.value()); Isolation isolation = attributes.getEnum("isolation"); rbta.setIsolationLevel(isolation.value()); rbta.setTimeout(attributes.getNumber("timeout").intValue()); rbta.setReadOnly(attributes.getBoolean("readOnly")); rbta.setQualifier(attributes.getString("value")); List<RollbackRuleAttribute> rollbackRules = new ArrayList<>(); for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) { rollbackRules.add(new RollbackRuleAttribute(rbRule)); } for (String rbRule : attributes.getStringArray("rollbackForClassName")) { rollbackRules.add(new RollbackRuleAttribute(rbRule)); } for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) { rollbackRules.add(new NoRollbackRuleAttribute(rbRule)); } for (String rbRule : attributes.getStringArray("noRollbackForClassName")) { rollbackRules.add(new NoRollbackRuleAttribute(rbRule)); } rbta.setRollbackRules(rollbackRules); return rbta; } 复制代码
我们的分析到这里,就已经可以知道了Spring 中对事务注解的解析过程,逻辑基本和 Spring Aop 类似。
@EnableTransactionManagement
通过引入 TransactionManagementConfigurationSelector
注册了 AutoProxyRegistrar
和 ProxyTransactionManagementConfiguration
两个类。
AutoProxyRegistrar
中注册了 InfrastructureAdvisorAutoProxyCreator 自动代理创建器 InfrastructureAdvisorAutoProxyCreator 中拦截bean的创建过程,通过 BeanFactoryTransactionAttributeSourceAdvisor 来判断bean中是否有事务注解,有则进行代理。 在上面的逻辑中,我们似乎没有发现Spring事务代理的具体过程,实际上代理的过程是在TransactionInterceptor
中。
4.3 TransactionInterceptor
在 Aop 的分析文章中,我们知道了无论是 Jdk代理还是 Cglib代理,其增强实现都是调用 Advisor
中的 Advice
实现。 BeanFactoryTransactionAttributeSourceAdvisor
作为 Advisor 的实现类,自然要遵从 Advisor 的处理方式,当代理被调用时会调用这个类的增强方法,也就是此bean 的Advice ,而在解析事务标签是,我们把 TransactionInterceptor
注入到了 BeanFactoryTransactionAttributeSourceAdvisor
中,所以调用事务增强器增强代理类的时会首先执行 TransactionInterceptor
进行增强,同时也就是 TransactionInterceptor#invoke
完成了整个事务的逻辑。
所以我们这里自然要看 TransactionInterceptor#invoke 方法。
public Object invoke(MethodInvocation invocation) throws Throwable { // Work out the target class: may be {@code null}. // The TransactionAttributeSource should be passed the target class // as well as the method, which may be from an interface. Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); // Adapt to TransactionAspectSupport's invokeWithinTransaction... // todo 在事务修饰下执行方法 return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() { @Override @Nullable public Object proceedWithInvocation() throws Throwable { return invocation.proceed(); } @Override public Object getTarget() { return invocation.getThis(); } @Override public Object[] getArguments() { return invocation.getArguments(); } }); } 复制代码
可以看到核心逻辑都在 invokeWithinTransaction
方法中,这里调用的 invokeWithinTransaction
方法 实际是 TransactionAspectSupport#invokeWithinTransaction
方法。所以下面我们来看看 TransactionAspectSupport#invokeWithinTransaction
方法的具体实现
TransactionAspectSupport#invokeWithinTransaction @Nullable protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation) throws Throwable { // If the transaction attribute is null, the method is non-transactional. // 获取事务数据源,这里获取的数据源就是在 TransactionInterceptor 注入的时候的设置的属性transactionAttributeSource = AnnotationTransactionAttributeSource。 // 在 ProxyTransactionManagementConfiguration 中完成 TransactionAttributeSource tas = getTransactionAttributeSource(); // 1. 获取对应的事务属性 final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null); // 2. 获取一个合适的 TransactionManager final TransactionManager tm = determineTransactionManager(txAttr); // 3. 对于反应式事务的处理 // 从Spring Framework 5.2 M2开始,Spring通过ReactiveTransactionManagerSPI 支持响应式/反应式事务管理 if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) { ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> { if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) { throw new TransactionUsageException( "Unsupported annotated transaction on suspending function detected: " + method + ". Use TransactionalOperator.transactional extensions instead."); } ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType()); if (adapter == null) { throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " + method.getReturnType()); } return new ReactiveTransactionSupport(adapter); }); return txSupport.invokeWithinTransaction( method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm); } // 判断 tm是否是 PlatformTransactionManager 类型,是则强转,不是则抛出异常 PlatformTransactionManager ptm = asPlatformTransactionManager(tm); // 构造方法的唯一标识( 全路径了类名.方法) final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); // 4. 对不同事务情景的处理 // 声明式事务的处理 // 如果txAttr为空或者tm 属于非CallbackPreferringPlatformTransactionManager,执行目标增强 // 在TransactionManager上,CallbackPreferringPlatformTransactionManager实现PlatformTransactionManager接口,暴露出一个方法用于执行事务处理中的回调 if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) { // Standard transaction demarcation with getTransaction and commit/rollback calls. // 5.如果有必要,创建事务信息。主要由于事务的传播属性,所以这里并不一定会创建事务 TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification); Object retVal; try { // This is an around advice: Invoke the next interceptor in the chain. // This will normally result in a target object being invoked. // 6. 执行被增强的方法 retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { // target invocation exception // 7. 异常回滚 completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { // 8. 提交之前清除事务信息 cleanupTransactionInfo(txInfo); } if (vavrPresent && VavrDelegate.isVavrTry(retVal)) { // Set rollback-only in case of Vavr failure matching our rollback rules... TransactionStatus status = txInfo.getTransactionStatus(); if (status != null && txAttr != null) { retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status); } } // 9.提交事务 commitTransactionAfterReturning(txInfo); return retVal; } // 编程式事务(CallbackPreferringPlatformTransactionManager)的处理。这里的逻辑基本都被封装了 else { final ThrowableHolder throwableHolder = new ThrowableHolder(); try { // 直接调用execute 方法。由于事务的提交回滚等操作都已经封装好了,所以这里并没有对事务进行详细的操作。 Object result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> { // 准备事务信息 TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status); try { // 执行方法 Object retVal = invocation.proceedWithInvocation(); if (vavrPresent && VavrDelegate.isVavrTry(retVal)) { // Set rollback-only in case of Vavr failure matching our rollback rules... retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status); } return retVal; } catch (Throwable ex) { if (txAttr.rollbackOn(ex)) { // A RuntimeException: will lead to a rollback. if (ex instanceof RuntimeException) { throw (RuntimeException) ex; } else { throw new ThrowableHolderException(ex); } } else { // A normal return value: will lead to a commit. throwableHolder.throwable = ex; return null; } } finally { // 清除事务信息 cleanupTransactionInfo(txInfo); } }); // Check result state: It might indicate a Throwable to rethrow. if (throwableHolder.throwable != null) { throw throwableHolder.throwable; } return result; } catch (ThrowableHolderException ex) { throw ex.getCause(); } catch (TransactionSystemException ex2) { if (throwableHolder.throwable != null) { logger.error("Application exception overridden by commit exception", throwableHolder.throwable); ex2.initApplicationException(throwableHolder.throwable); } throw ex2; } catch (Throwable ex2) { if (throwableHolder.throwable != null) { logger.error("Application exception overridden by commit exception", throwableHolder.throwable); } throw ex2; } } } 复制代码
从上面的代码中,我们可以知道 Spring支持声明式事务和编程式事务
两种处理。两者的实现本质基本相同。在invoke方法中我们也可以看到这两种方式的实现,通常我们使用的都是通过 @Transactional
注解修饰的声明式事务,所以我们下面主要分析 声明式事务 的处理过程。
-
获取事务属性
TransactionAttribute
,TransactionAttribute
中包含 传播属性,timeout
等事务属性信息。如果是使用@Transactional
注解,这个解析过程是在AnnotationTransactionAttributeSource#findTransactionAttribute(java.lang.reflect.Method)
中完成。 -
加载配置中的
TrancationManager
, 事务管理器,是事务实现的基础,我们这里获取到的是DataSourceTransactionManager
。 -
对反应式事务的处理。
-
不同事务处理方式使用不同的逻辑。在上面的代码中主要是两种情况,一是声明式事务,这种情况是通过
@Transactional
注解修饰方法来表示开启事务。另一种情况是编程式事务,即可以通过xml方式或者配置类方式来进行完成事务功能,其实TransactionTemplate 的实现就是编程式事务,但通过TransactionTemplate
并不会走到这个逻辑,这里的编程式事务应该单独是通过xml或者配置类方式来配置的。- 对于声明式事务的处理和编程式事务的处理,区别主要在两点。一是事务属性上,因为编程式事务是不需要事务属性的,二是
TransactionManager
的不同,CallbackPreferringPlatformTransactionManager
实现了PlatformTransactionManager
接口,暴露了一个方法用于执行事务处理中的回调。所以这两种方式都可以作为事务处理方式的判断。
- 对于声明式事务的处理和编程式事务的处理,区别主要在两点。一是事务属性上,因为编程式事务是不需要事务属性的,二是
-
在目标方法执行前获取事务并收集事务信息。
- 事务信息与事务属性并不相同,也就是
TransactionInfo
和TransactionAttribute
并不相同,TransactionInfo
中包含TransactionAttribute
信息,并且处理TransactionAttribute
之外还有其他事物信息,比如PlatformTransactionManager
以及TransactionStatus
相关信息。
- 事务信息与事务属性并不相同,也就是
-
执行目标方法
-
如果出现异常,则进行回滚。这里需要注意,默认的情况下只有
RuntimeException
异常才会执行回滚。可以通过@Transactional(rollbackFor = Exception.class)
的方式来指定触发回滚的异常 -
提交事务前的事务信息清除
-
提交事务
-
若是 编程式事务,则直接执行execute方法即可,这里就不再讲解。
注: PlatformTransactionManager
和 ReactiveTransactionManager
二者都是为了实现事务, PlatformTransactionManager
在内部进行事务执行流程的封装,并且暴露出来一个 execute
方法用于执行事务的具体信息, TransactionTemplate
的声明式事务就是基于此实现的。而 ReactiveTransactionManager
则是比较原始的,需要我们自己来实现事务的整个逻辑。
上面比较笼统的讲了事务的实现,下面们主要分析以下三个方法,也是事务的的关键流程:
createTransactionIfNecessary completeTransactionAfterThrowing commitTransactionAfterReturning