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
支持三个不同的事务注解 :
Spring
事务注解 org.springframework.transaction.annotation.Transactional
JTA
事务注解 javax.transaction.Transactional
EJB 3
事务注解 javax.ejb.TransactionAttribute
因为历史原因,存在上面三种事务注解方式,这一点这里不过多解释。但这里需要提醒的是:
以上事务注解对服务方法所要使用的事务从以下方面做了定义:
请注意: 具体到每个注解,对以上属性的支持有所不同,请参考相应注解的定义 。
当遇到以上三种注解的某一个时,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
是给调用者使用的获取指定方法的事务注解属性的入口。
方法AbstractFallbackTransactionAttributeSource#getTransactionAttribute
接收两个参数 :
method
– 目前正在进行的方法调用targetClass
– 真正要调用的方法所在的类注意这里细微的差别 : method
的声明类(也就是所属类)不一定是targetClass
,但targetClass
一定会有一个方法和method
的方法签名相同。通常情况下,method
的声明类/所属类会是targetClass
的某个祖先类或者实现的某个接口。
方法AbstractFallbackTransactionAttributeSource#getTransactionAttribute
按如下顺序依次尝试获取事务注解属性 :
specific target method
– 和method
相同签名的targetClass
上的那个方法target class
– 也就是参数targetClass
declaring method
– 也就是参数method
declaring class/interface
– method
的声明类/所属类并对所发现的事务注解属性进行了缓存。
注意 : 如果某个方法和该方法所属类上都有事务注解属性,优先使用方法上的事务注解属性。
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;
}
}