Spring Transaction 5.1.3 源代码分析 : AnnotationTransactionAttributeSource 解析注解式事务属性

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/andy_zhang2007/article/details/85846066

概述

Spring支持使用注解指定服务方法的事务属性。这些事务注解可以用在类上,也可以用在方法上,如下例子所示 。

Spring事务注解例子–应用在类级别

将事务注解标记到服务组件类级别,相当于为该服务组件的每个服务方法都应用了这个注解。

import org.springframework.transaction.annotation.Transactional;
// 这里省略其他与本文主题无关的import

@Transactional
@Service
public class EmployeeService {
	// 当前服务组件的一个服务方法,
	// 因为该服务组件使用了注解@Transactional,所以该服务组件的每个服务方法都会应用该注解属性
    public long add(String name) {
		// ...	        
    }
    // 省略该服务组件的其他实现部分
	// ... 
}

Spring事务注解例子–应用在方法级别

跟将事务注解放在类层面相比,将事务注解应用在方法级别,是更细粒度的一种事务注解方式。这个服务组件的不同服务方法可以采用自己不同的事务注解。

下面的例子演示了在同一服务组件中,不同的方法使用不同的事务注解定义。

import javax.transaction.Transactional;
import static javax.transaction.Transactional.TxType.NOT_SUPPORTED;
// 这里省略其他与本文主题无关的import
@Service
public class StudentService {
    @Autowired
    StudentRepository repo;


    @Transactional
    public long add(String name, String studentNo, long classId) {
    	// 省略具体实现
    }

    @Transactional(NOT_SUPPORTED)
    public long findByStudentNo(String studentNo) {
    	// 省略具体实现
    }

另外,Spring 支持三个不同的事务注解 :

  1. Spring 事务注解 org.springframework.transaction.annotation.Transactional
  2. JTA事务注解 javax.transaction.Transactional
  3. EJB 3 事务注解 javax.ejb.TransactionAttribute

因为历史原因,存在上面三种事务注解方式,这一点这里不过多解释。但这里需要提醒的是:

  1. 上面三种方式具体使用的方式不完全一样,使用时要注意各自具体的使用方式;
  2. 上面三种方式的目的/语义是一致的。

以上事务注解对服务方法所要使用的事务从以下方面做了定义:

  • 事务传播方式
  • 事务隔离级别
  • 事务超时时间
  • 是否只读事务
  • 遇到哪些异常回滚事务
  • 遇到哪些异常不要回滚事务

请注意: 具体到每个注解,对以上属性的支持有所不同,请参考相应注解的定义 。

当遇到以上三种注解的某一个时,Spring会使用AnnotationTransactionAttributeSource分析该事务注解,最终组织成一个TransactionAttribute供随后使用。本文将基于源代码解析该过程。

源代码解析

AnnotationTransactionAttributeSource

package org.springframework.transaction.annotation;

import java.io.Serializable;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;

import org.springframework.lang.Nullable;
import org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

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();
		// 根据注解类的存在性判断 JTA 1.2 事务注解是否被使用
		jta12Present = ClassUtils.isPresent("javax.transaction.Transactional", classLoader);
		// 根据注解类的存在性判断 EJB 3 事务注解是否被使用
		ejb3Present = ClassUtils.isPresent("javax.ejb.TransactionAttribute", classLoader);
	}

	// 指出仅仅处理public方法(基于代理的AOP情况下的典型做法),
	// 还是也处理protected/private方法(使用AspectJ类织入方式下的典型做法)
	private final boolean publicMethodsOnly;

	// 保存用于分析事务注解的事务注解分析器
	private final Set<TransactionAnnotationParser> annotationParsers;


	// 构造函数, publicMethodsOnly 缺省使用 true
	public AnnotationTransactionAttributeSource() {
		this(true);
	}

	// 构造函数
	public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
		this.publicMethodsOnly = publicMethodsOnly;
		// 下面这段逻辑主要是准备用于分析事务注解的各个分析器,放到属性 annotationParsers 中
		// Spring事务注解分析器总是
		// 会被使用 : SpringTransactionAnnotationParser
		if (jta12Present || ejb3Present) {
			// 根据 JTA , EJB 事务注解类的存在性决定要不要添加相应的事务注解处理器
			// JTA 事务注解分析器 : JtaTransactionAnnotationParser
			// EJB 事务注解分析器 : Ejb3TransactionAnnotationParser
			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.
	 * 创建一个定制的 AnnotationTransactionAttributeSource ,使用给定的事务注解分析器(一个),
	 * publicMethodsOnly 缺省使用 true,仅针对public方法工作
	 * @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.
	 * 创建一个定制的 AnnotationTransactionAttributeSource ,使用给定的事务注解分析器(多个),
	 * publicMethodsOnly 缺省使用 true,仅针对public方法工作
	 * @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.
     * 创建一个定制的 AnnotationTransactionAttributeSource ,使用给定的事务注解分析器(多个),
	 * publicMethodsOnly 缺省使用 true,仅针对public方法工作
	 * @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) {
		// Class 实现了 AnnotatedElement 接口,所以交给下面的 
		// determineTransactionAttribute(AnnotatedElement)执行具体的分析逻辑
		return determineTransactionAttribute(clazz);
	}

	// 获取某个方法上的事务注解属性
	@Override
	@Nullable
	protected TransactionAttribute findTransactionAttribute(Method method) {
		// Method 实现了 AnnotatedElement 接口,所以交给下面的 
		// determineTransactionAttribute(AnnotatedElement)执行具体的分析逻辑	
		return determineTransactionAttribute(method);
	}

	/**
	 * Determine the transaction attribute for the given method or class.
	 * 分析获取某个被注解的元素,具体的来讲,指的是一个类或者一个方法上的事务注解属性。
	 * 该实现会遍历自己属性annotationParsers中所包含的事务注解属性分析器试图获取事务注解属性,
	 * 一旦获取到事务注解属性则返回,如果获取不到则返回null,表明目标类/方法上没有事务注解。
	 */
	@Nullable
	protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
		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.
	 * 缺省情况下,仅仅public方法上的事务注解才被识别和应用
	 */
	@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();
	}

}

从类 AnnotationTransactionAttributeSource的源代码可以看到,它仅仅通过protected的方法实现类如何找到指定类/方法的事务注解属性,但是自身并没有提供public方法供调用者使用。实际上,类 AnnotationTransactionAttributeSource提供给调用者的服务方法是public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass),而该方法定义在其父类AbstractFallbackTransactionAttributeSource中。

抽象类 AbstractFallbackTransactionAttributeSource

AbstractFallbackTransactionAttributeSource是接口TransactionAttributeSource的抽象实现,也是上面提到的工具类AnnotationTransactionAttributeSource的父类。方法AbstractFallbackTransactionAttributeSource#getTransactionAttribute是给调用者使用的获取指定方法的事务注解属性的入口。

扫描二维码关注公众号,回复: 4886495 查看本文章

方法AbstractFallbackTransactionAttributeSource#getTransactionAttribute接收两个参数 :

  • method – 目前正在进行的方法调用
  • targetClass – 真正要调用的方法所在的类

注意这里细微的差别 : method的声明类(也就是所属类)不一定是targetClass,但targetClass一定会有一个方法和method的方法签名相同。通常情况下,method的声明类/所属类会是targetClass的某个祖先类或者实现的某个接口。

方法AbstractFallbackTransactionAttributeSource#getTransactionAttribute按如下顺序依次尝试获取事务注解属性 :

  1. specific target method – 和method相同签名的targetClass上的那个方法
  2. target class – 也就是参数targetClass
  3. declaring method – 也就是参数method
  4. declaring class/interfacemethod的声明类/所属类

并对所发现的事务注解属性进行了缓存。

注意 : 如果某个方法和该方法所属类上都有事务注解属性,优先使用方法上的事务注解属性。

package org.springframework.transaction.interceptor;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.aop.support.AopUtils;
import org.springframework.core.MethodClassKey;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;

public abstract class AbstractFallbackTransactionAttributeSource implements TransactionAttributeSource {

	/**
	 * Canonical value held in cache to indicate no transaction attribute was
	 * found for this method, and we don't need to look again.
	 * 针对没有事务注解属性的方法进行事务注解属性缓存时使用的特殊值,用于标记该方法没有事务注解属性,
	 * 从而不用在首次缓存在信息后,不用再次重复执行真正的分析
	 */
	@SuppressWarnings("serial")
	private static final TransactionAttribute NULL_TRANSACTION_ATTRIBUTE = new DefaultTransactionAttribute() {
		@Override
		public String toString() {
			return "null";
		}
	};


	/**
	 * Logger available to subclasses.
	 * As this base class is not marked Serializable, the logger will be recreated
	 * after serialization - provided that the concrete subclass is Serializable.
	 */
	protected final Log logger = LogFactory.getLog(getClass());

	/**
	 * Cache of TransactionAttributes, keyed by method on a specific target class.
	 * As this base class is not marked Serializable, the cache will be recreated
	 * after serialization - provided that the concrete subclass is Serializable.
	 * TransactionAttribute 
	 * 方法上的事务注解属性缓存,key使用目标类上的方法,使用类型MethodClassKey来表示
	 */
	private final Map<Object, TransactionAttribute> attributeCache = new ConcurrentHashMap<>(1024);


	/**
	 * Determine the transaction attribute for this method invocation.
	 * 获取指定方法上的注解事务属性
	 * Defaults to the class's transaction attribute if no method attribute is found.
	 * 如果方法上没有注解事务属性,则使用目标方法所属类上的注解事务属性
	 * @param method the method for the current invocation (never null)
	 * @param targetClass the target class for this invocation (may be null)
	 * @return a TransactionAttribute for this method, or null if the method
	 * is not transactional
	 */
	@Override
	@Nullable
	public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
		if (method.getDeclaringClass() == Object.class) {
			// 如果目标方法是内置类Object上的方法,总是返回null,这些方法上不应用事务
			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) {
			// 目标方法上上并没有事务注解属性,但是已经被尝试分析过并且已经被缓存,
			// 使用的值是 NULL_TRANSACTION_ATTRIBUTE,所以这里再次尝试获取其注解事务属性时,
			// 直接返回 null
				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) {
				// 如果目标方法上并没有使用注解事务属性,也缓存该信息,只不过使用的值是一个特殊值:
				// NULL_TRANSACTION_ATTRIBUTE , 此特殊值表明目标方法上没有使用注解事务属性
				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;
		}
	}

	/**
	 * Determine a cache key for the given method and target class.
	 * Must not produce same key for overloaded methods.
	 * Must produce same key for different instances of the same method.
	 * @param method the method (never null)
	 * @param targetClass the target class (may be null)
	 * @return the cache key (never null)
	 */
	protected Object getCacheKey(Method method, @Nullable Class<?> targetClass) {
		return new MethodClassKey(method, targetClass);
	}

	/**
	 * 
	 * 查找目标方法上的事务注解属性,但只是查找和返回,并不做缓存,效果上讲,可以认为
	 * #getTransactionAttribute 是增加了缓存机制的方法#computeTransactionAttribute
	 * 
	 * As of 4.1.8, this method can be overridden.
	 * @since 4.1.8
	 * @see #getTransactionAttribute
	 */
	@Nullable
	protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
		// Don't allow no-public methods as required.
		if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
			// 如果事务注解属性分析仅仅针对public方法,而当前方法不是public,则直接返回null
			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 可能是基于接口的方法,该接口和参数targetClass所对应的类不同(也就是说:
		// targetClass是相应接口的某个实现类),而我们这里需要的属性是要来自targetClass的,
		// 所以这里先获取targetClass上的那个和method对应的方法,这里 method, specificMethod 
		// 都可以认为是潜在的目标方法
		Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

		// First try is the method in the target class.
		// 首先尝试检查事务注解属性直接标记在目标方法 specificMethod 上
		TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
		if (txAttr != null) {
			// 事务注解属性直接标记在目标方法上
			return txAttr;
		}

		// Second try is the transaction attribute on the target class.
		// 然后尝试检查事务注解属性是否标记在目标方法 specificMethod 所属类上
		txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
		if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
			// 事务注解属性是否标记在目标方法所属类上
			return txAttr;
		}

		// 逻辑走到这里说明目标方法specificMethod,也就是实现类上的目标方法上没有标记事务注解属性
		if (specificMethod != method) {
			// Fallback is to look at the original method.
			// 如果 specificMethod 和 method 不同,则说明 specificMethod 是具体实现类
			// 的方法,method 是实现类所实现接口的方法,现在尝试从 method 上获取事务注解属性
			txAttr = findTransactionAttribute(method);
			if (txAttr != null) {
				return txAttr;
			}
			// Last fallback is the class of the original method.
			// 现在尝试在 method 所属类上查看是否有事务注解属性
			txAttr = findTransactionAttribute(method.getDeclaringClass());
			if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
				return txAttr;
			}
		}

		// specificMethod 方法/所属类上没有事务注解属性,
		// method 方法/所属类上也没有事务注解属性,
		// 所以返回 null
		return null;
	}


	/**
	 * Subclasses need to implement this to return the transaction attribute for the
	 * given class, if any.
	 * 从指定类上获取事务注解属性,由子类负责提供实现
	 * @param clazz the class to retrieve the attribute for
	 * @return all transaction attribute associated with this class, or null if none
	 */
	@Nullable
	protected abstract TransactionAttribute findTransactionAttribute(Class<?> clazz);

	/**
	 * Subclasses need to implement this to return the transaction attribute for the
	 * given method, if any.
	 * 从指定方法上获取事务注解属性,由子类负责提供实现
	 * @param method the method to retrieve the attribute for
	 * @return all transaction attribute associated with this method, or null if none
	 */
	@Nullable
	protected abstract TransactionAttribute findTransactionAttribute(Method method);

	/**
	 * Should only public methods be allowed to have transactional semantics?
	 * The default implementation returns false.
	 */
	protected boolean allowPublicMethodsOnly() {
		return false;
	}

}

猜你喜欢

转载自blog.csdn.net/andy_zhang2007/article/details/85846066