Spring5源码15-事务(AutoProxyRegistrar和ProxyTransactionManagementConfiguration)

1,677 阅读18分钟

欢迎大家关注 github.com/hsfxuebao ,希望对大家有所帮助,要是觉得可以的话麻烦给点一下Star哈

1. 案例(注解版)

  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'
     }
    
  2. 注解版配置文件
@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());
   }

}
  1. 实例类
@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();
   }
}
  1. 测试类
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

image.png

可以看到,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);
	}

}

到这里就可以看到了,默认情况下,我们引入了两个类,AutoProxyRegistrarProxyTransactionManagementConfiguration

  • AutoProxyRegistrar : 主要是注册了 InfrastructureAdvisorAutoProxyCreator 自动代理创建器。而 InfrastructureAdvisorAutoProxyCreator 的逻辑基本上和 Aop 的逻辑相同
  • ProxyTransactionManagementConfiguration : 注册了事务实现的核心 Bean,包括 BeanFactoryTransactionAttributeSourceAdvisorTransactionAttributeSourceTransactionInterceptor

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 的内容

image.png

可以看到 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;
	}

}

这个根据上面的分析,我们可以知道这个是事务判断的核心,BeanFactoryTransactionAttributeSourceAdvisorAdvisor 子类,那么我们可以知道其中有两个关键属性: 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) 返回true
  • pc.getMethodMatcher().matches(method, targetClass) 返回true

如下图,具体实现在 AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class<?>, boolean) 中,这里第二点不考虑,因为在这里不会为True

image.png

通过 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 注册了 AutoProxyRegistrarProxyTransactionManagementConfiguration 两个类。

  • 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 注解修饰的声明式事务,所以我们下面主要分析 声明式事务 的处理过程。

  1. 获取事务属性 TransactionAttributeTransactionAttribute 中包含 传播属性,timeout 等事务属性信息。如果是使用 @Transactional 注解,这个解析过程是在AnnotationTransactionAttributeSource#findTransactionAttribute(java.lang.reflect.Method) 中完成。

  2. 加载配置中的 TrancationManager, 事务管理器,是事务实现的基础,我们这里获取到的是 DataSourceTransactionManager

  3. 对反应式事务的处理。

  4. 不同事务处理方式使用不同的逻辑。在上面的代码中主要是两种情况,一是声明式事务,这种情况是通过 @Transactional 注解修饰方法来表示开启事务。另一种情况是编程式事务,即可以通过xml方式或者配置类方式来进行完成事务功能,其实TransactionTemplate 的实现就是编程式事务,但通过TransactionTemplate并不会走到这个逻辑,这里的编程式事务应该单独是通过xml或者配置类方式来配置的。

    • 对于声明式事务的处理和编程式事务的处理,区别主要在两点。一是事务属性上,因为编程式事务是不需要事务属性的,二是 TransactionManager 的不同,CallbackPreferringPlatformTransactionManager 实现了 PlatformTransactionManager 接口,暴露了一个方法用于执行事务处理中的回调。所以这两种方式都可以作为事务处理方式的判断。
  5. 在目标方法执行前获取事务并收集事务信息。

    • 事务信息与事务属性并不相同,也就是 TransactionInfoTransactionAttribute 并不相同,TransactionInfo 中包含TransactionAttribute 信息,并且处理 TransactionAttribute 之外还有其他事物信息,比如PlatformTransactionManager 以及 TransactionStatus相关信息。
  6. 执行目标方法

  7. 如果出现异常,则进行回滚。这里需要注意,默认的情况下只有 RuntimeException 异常才会执行回滚。可以通过 @Transactional(rollbackFor = Exception.class) 的方式来指定触发回滚的异常

  8. 提交事务前的事务信息清除

  9. 提交事务

  10. 若是 编程式事务,则直接执行execute方法即可,这里就不再讲解。

注: PlatformTransactionManagerReactiveTransactionManager 二者都是为了实现事务,PlatformTransactionManager 在内部进行事务执行流程的封装,并且暴露出来一个 execute 方法用于执行事务的具体信息,TransactionTemplate 的声明式事务就是基于此实现的。而 ReactiveTransactionManager 则是比较原始的,需要我们自己来实现事务的整个逻辑。

上面比较笼统的讲了事务的实现,下面们主要分析以下三个方法,也是事务的的关键流程:

  • 事务的创建 - createTransactionIfNecessary
  • 事务的回滚 - completeTransactionAfterThrowing
  • 事务的提交 - commitTransactionAfterReturning

参考文章

Spring5源码注释github地址
Spring源码深度解析(第2版)
spring源码解析
Spring源码深度解析笔记
Spring注解与源码分析
Spring注解驱动开发B站教程