Spring Transaction : AnnotationTransactionAttributeSource

本文深入探讨了Spring框架中AnnotationTransactionAttributeSource类的功能与使用,它是如何从类或方法上的事务注解中分析并获取事务属性,以及在SpringBoot应用中的配置与运行流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

这是一个TransactionAttributeSource 接口的实现类,用于从类或者方法上事务注解分析相应的事务属性。它读取Spring的注解@TransactionalJTA 1.2+注解@Transactional(位于包javax.transaction),或者EJB 3的注解@TransactionAttribute(位于包javax.ejb),得到相应的事务属性给调用者使用。该工具类并不是设计给应用开发人员的,是一个Spring框架内部使用的工具。

该类也可以充当自定义TransactionAttributeSource的基类,或者通过TransactionAnnotationParser策略机制进行定制。

关于应用

1. 引入

配置类ProxyTransactionManagementConfiguration定义了一个实际类型为AnnotationTransactionAttributeSourcebean ,并将该bean传递给另外一个TransactionInterceptor bean作为获取事务注解属性的工具使用 :

// ProxyTransactionManagementConfiguration 代码片段
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor() {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		interceptor.setTransactionAttributeSource(transactionAttributeSource());
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}
    
  1. 该配置类ProxyTransactionManagementConfiguration会被TransactionManagementConfigurationSelector导入;
  2. TransactionManagementConfigurationSelector会被注解@EnableTransactionManagement导入;
  3. 而对于一个Spring Boot应用,注解@EnableTransactionManagement会被自动配置类TransactionAutoConfiguration使用。

2. 使用

    // TransactionAspectSupport  代码片段, 

	@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.
       // 这里的 tas ,在 Spring Boot 应用中,缺省就是 ProxyTransactionManagementConfiguration 中定义的
       // AnnotationTransactionAttributeSource bean
		TransactionAttributeSource tas = getTransactionAttributeSource();
       // 从方法上分析事务注解从而获取事务属性 
		final TransactionAttribute txAttr = (tas != null ? 
			tas.getTransactionAttribute(method, targetClass) : null);
		// ... 省略其他代码
	}	

源代码解析

源代码版本 : spring-tx-5.1.5.RELEASE

package org.springframework.transaction.annotation;

// 忽略 import 行

@SuppressWarnings("serial")
public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
		implements Serializable {

    // 用于记录 JTA 1.2 是否被使用
	private static final boolean jta12Present;

    // 用于记录 EJB 3 是否被使用
	private static final boolean ejb3Present;

	static {
		ClassLoader classLoader = AnnotationTransactionAttributeSource.class.getClassLoader();
		jta12Present = ClassUtils.isPresent("javax.transaction.Transactional", classLoader);
		ejb3Present = ClassUtils.isPresent("javax.ejb.TransactionAttribute", classLoader);
	}

    // 是否仅仅针对使用事务注解的 public 方法,而不针对 protected/private 方法
    // 缺省情况下初始值为 true
	private final boolean publicMethodsOnly;

   // 保存将要使用的事务注解解析器 
	private final Set<TransactionAnnotationParser> annotationParsers;


	/**
	 * Create a default AnnotationTransactionAttributeSource, supporting
	 * public methods that carry the {@code Transactional} annotation
	 * or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
	 */
	public AnnotationTransactionAttributeSource() {
		this(true);
	}

	/**
	 * Create a custom AnnotationTransactionAttributeSource, supporting
	 * public methods that carry the {@code Transactional} annotation
	 * or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
	 * @param publicMethodsOnly whether to support public methods that carry
	 * the {@code Transactional} annotation only (typically for use
	 * with proxy-based AOP), or protected/private methods as well
	 * (typically used with AspectJ class weaving)
	 */
	public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
		this.publicMethodsOnly = publicMethodsOnly;
       
       // 1. 总是添加 Spring 自身的事务属性解析器;
       // 2. 根据 JTA, EJB 包引入的情况决定是否要添加针对它们的事务属性解析器
		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());
		}
	}

	/**
	 * Create a custom AnnotationTransactionAttributeSource.
	 * @param annotationParser the TransactionAnnotationParser to use
	 */
	public AnnotationTransactionAttributeSource(TransactionAnnotationParser annotationParser) {
		this.publicMethodsOnly = true;
		Assert.notNull(annotationParser, "TransactionAnnotationParser must not be null");
		this.annotationParsers = Collections.singleton(annotationParser);
	}

	/**
	 * Create a custom AnnotationTransactionAttributeSource.
	 * @param annotationParsers the TransactionAnnotationParsers to use
	 */
	public AnnotationTransactionAttributeSource(TransactionAnnotationParser... annotationParsers) {
		this.publicMethodsOnly = true;
		Assert.notEmpty(annotationParsers, "At least one TransactionAnnotationParser needs to be specified");
		this.annotationParsers = new LinkedHashSet<>(Arrays.asList(annotationParsers));
	}

	/**
	 * Create a custom AnnotationTransactionAttributeSource.
	 * @param annotationParsers the TransactionAnnotationParsers to use
	 */
	public AnnotationTransactionAttributeSource(Set<TransactionAnnotationParser> annotationParsers) {
		this.publicMethodsOnly = true;
		Assert.notEmpty(annotationParsers, "At least one TransactionAnnotationParser needs to be specified");
		this.annotationParsers = annotationParsers;
	}


	@Override
	@Nullable
	protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
		return determineTransactionAttribute(clazz);
	}

	@Override
	@Nullable
	protected TransactionAttribute findTransactionAttribute(Method method) {
		return determineTransactionAttribute(method);
	}

	/**
	 * Determine the transaction attribute for the given method or class.
	 * <p>This implementation delegates to configured
	 * {@link TransactionAnnotationParser TransactionAnnotationParsers}
	 * for parsing known annotations into Spring's metadata attribute class.
	 * Returns {@code null} if it's not transactional.
	 * <p>Can be overridden to support custom annotations that carry transaction metadata.
	 * @param element the annotated method or class
	 * @return the configured transaction attribute, or {@code null} if none was found
	 */
	@Nullable
	protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
       // element 可以是个方法,也可以是个类
       // 遍历所指定的 annotationParsers ,尝试使用其中每一个从 element 上根据注解提取出
       // 事务属性到 attr,遇到第一个成功的立即结束
		for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
			TransactionAttribute attr = annotationParser.parseTransactionAnnotation(element);
			if (attr != null) {
				return attr;
			}
		}
        // 该方法上没有能处理的事务属性注解
		return null;
	}

	/**
	 * By default, only public methods can be made transactional.
	 */
	@Override
	protected boolean allowPublicMethodsOnly() {
		return this.publicMethodsOnly;
	}


	@Override
	public boolean equals(Object other) {
		if (this == other) {
			return true;
		}
		if (!(other instanceof AnnotationTransactionAttributeSource)) {
			return false;
		}
		AnnotationTransactionAttributeSource otherTas = (AnnotationTransactionAttributeSource) other;
		return (this.annotationParsers.equals(otherTas.annotationParsers) &&
				this.publicMethodsOnly == otherTas.publicMethodsOnly);
	}

	@Override
	public int hashCode() {
		return this.annotationParsers.hashCode();
	}

}

参考文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值