基于最新Spring 5.x,详细介绍了Spring 事务源码,包括BeanFactoryTransactionAttributeSourceAdvisor注解事务通知器源码解析。
此前,我们学习了< tx:annotation-driven/>标签和@EnableTransactionManagement注解的解析源码,他们的都会向IoC容器注入一些bena定义,这些bean将会在后续Spring事务的处理中发挥不同的作用, 现在我们来学习这些bean,首先我们学习BeanFactoryTransactionAttributeSourceAdvisor
。
Spring 5.x 源码汇总
Spring 事务源码(1)—<tx:advice/>事务标签源码解析
Spring 事务源码(2)—<tx:annotation-driven/>事务标签源码解析
Spring 事务源码(3)—@EnableTransactionManagement事务注解源码解析
Spring 事务源码(4)—BeanFactoryTransactionAttributeSourceAdvisor注解事务通知器源码解析
Spring 事务源码(5)—TransactionInterceptor事务拦截器与事务的AOP增强实现
Spring 事务源码(6)—createTransactionIfNecessary处理事务属性并尝试创建事务【两万字】
Spring 事务源码(7)—事务的completeTransactionAfterThrowing回滚、commitTransactionAfterReturning提交以及事务源码总结【一万字】
无论是
标签还是@EnableTransactionManagement
注解,都会向容器注入一个BeanFactoryTransactionAttributeSourceAdvisor
的bean定义。
它的uml类图如下:
它是一个Advisor
类型的通知器实例,内部的transactionAttributeSource为AnnotationTransactionAttributeSource,advice为TransactionInterceptor。
它的pointcut是一个TransactionAttributeSourcePointcut
的匿名内部类实例,其内部的getTransactionAttributeSource
保存了设置的AnnotationTransactionAttributeSource
。
public class BeanFactoryTransactionAttributeSourceAdvisor extends
AbstractBeanFactoryPointcutAdvisor {
/**
* 事务属性源
*/
@Nullable
private TransactionAttributeSource transactionAttributeSource;
/**
* 事务切入点,用于判断某个bean/方法是否符合Spring事务切入规则
*/
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
/**
* 设置用于查找TransactionAttribute的TransactionAttributeSource。
*
* @see TransactionInterceptor#setTransactionAttributeSource
*/
public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
this.transactionAttributeSource = transactionAttributeSource;
}
/**
* 为这个切入点设置要使用的ClassFilter类筛选器。默认是ClassFilter.TRUE,即匹配所有类
*/
public void setClassFilter(ClassFilter classFilter) {
this.pointcut.setClassFilter(classFilter);
}
/**
* 获取切入点
*/
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
}
在普通bean被实例化之后将通过AutoProxyCreator的postProcessAfterInitialization方法来判断当前bean是否可以被代理,其中就自然会通过BeanFactoryTransactionAttributeSourceAdvisor进行匹配,在匹配的时候它实际上就是通过解析对应的类、方法上的Spring事务注解(比如@Transactional)来进行匹配的,这就是解析@Transactional注解的入口。
TransactionAttributeSourcePointcut
作为事务通知器的切入点,通知器就是靠此对象来判断某个bean是否可以被此事务通知器增强,简单的说就是判断当前bean是否可以应用这一个事务。
在AutoProxyCreator的postProcessAfterInitialization方法中(内部的canApply方法,源码我们在此前的通用Spring AOP的AspectJAwareAdvisorAutoProxyCreator部分已经讲过了),Pointcut的通用匹配逻辑就是:
ClassFilter.matches
方法进行匹配,在TransactionAttributeSourcePointcut的构造器中调用了setClassFilter方法,将ClassFilter配置为一个TransactionAttributeSourceClassFilter。MethodMatcher.matches
对方法一一进行匹配。最终,如果至少有一个方法能够被增强,那么表示当前bean实例就能被当然通知器,也就可以创建代理对象。下面我们来看看TransactionAttributeSourcePointcut的具体逻辑!
很简单,两个判断逻辑:
TransactionalProxy或者PersistenceExceptionTranslator
,这些类型要么表示当前bean属于已经进行了手动事务代理,要么表示当前bean属于事务管理的基础bean,这些类的实例的方法不应该进行Spring事务的代理。isCandidateClass方法返回true
,那么表示当前bean的class允许继续匹配方法,否则表示不会继续匹配,即当前bean实例不会进行事务代理。abstract class TransactionAttributeSourcePointcut extends
StaticMethodMatcherPointcut implements Serializable {
/**
* 设置ClassFilter为一个TransactionAttributeSourceClassFilter实例
*/
protected TransactionAttributeSourcePointcut() {
setClassFilter(new TransactionAttributeSourceClassFilter());
}
/**
* 获取底层的TransactionAttributeSource(可以为null)。由子类实现。
*
* 在BeanFactoryTransactionAttributeSourceAdvisor中的TransactionAttributeSourcePointcut就是一个匿名内部类实现
* 它的getTransactionAttributeSource会返回配置的AnnotationTransactionAttributeSource事务属性源
*/
@Nullable
protected abstract TransactionAttributeSource getTransactionAttributeSource();
/**
* 实际工作委托给TransactionAttributeSource的类过滤器。
* TransactionAttributeSource的isCandidateClass方法用于过滤那些方法不值继续得搜索的类。
*/
private class TransactionAttributeSourceClassFilter implements ClassFilter {
/**
* 匹配类的方法
*
* @param clazz bean的class
* @return true 成功 false 失败
*/
@Override
public boolean matches(Class<?> clazz) {
//如果当前bean的类型属于TransactionalProxy或者TransactionalProxy或者PersistenceExceptionTranslator
//那么返回false,这些类的实例的方法不应该进行Spring 事务的代理
if (TransactionalProxy.class.isAssignableFrom(clazz) ||
TransactionManager.class.isAssignableFrom(clazz) ||
PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
return false;
}
//如果不是上面那些类型的bean实例,就通过设置的TransactionAttributeSource来判断
//如果TransactionAttributeSource不为null并且isCandidateClass方法返回true,
//那么表示当前bean的class允许继续匹配方法,否则表示不会继续匹配,即当前bean实例不会进行事务代理
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.isCandidateClass(clazz));
}
}
}
在BeanFactoryTransactionAttributeSourceAdvisor中的TransactionAttributeSourcePointcut就是一个匿名内部类实现,它的getTransactionAttributeSource会返回配置的AnnotationTransactionAttributeSource事务属性源。
AnnotationTransactionAttributeSource是专门用于获取基于注解的Spring声明式事务管理的事务属性的属性源。
并且除了Spring的org.springframework.transaction.annotation.Transactional注解之外,还支持JTA 1.2的javax.transaction.Transactional事务注解以及EJB3的javax.ejb.TransactionAttribute事务注解。
在创建时,将会调用它的默认无参构造器。将会为对应的事务注解配置对应的注解解析器,并且默认情况下,仅支持对类中公共的方法进行事务代理。
也就是说,如果采用Spring AOP的基于注解的声明式事务控制,那么仅支持public方法,这一点,相比于普通的Spring AOP的代理范围更窄,这是我们一定要注意的!如果需要非public方法注解生效,那么应该使用底层基于AspectJ的静态织入。
/*AnnotationTransactionAttributeSource的相关属性和方法*/
/**
* 是否存在JTA 1.2的javax.transaction.Transactional事务注解
*/
private static final boolean jta12Present;
/**
* 是否存在EJB3的javax.ejb.TransactionAttribute事务注解
*/
private static final boolean ejb3Present;
/*
* 在静态块中判断是否存在其他外部框架的事务注解
* JTA 1.2的javax.transaction.Transactional事务注解
* EJB3的javax.ejb.TransactionAttribute事务注解
*/
static {
ClassLoader classLoader = AnnotationTransactionAttributeSource.class.getClassLoader();
jta12Present = ClassUtils.isPresent("javax.transaction.Transactional", classLoader);
ejb3Present = ClassUtils.isPresent("javax.ejb.TransactionAttribute", classLoader);
}
/**
* 是否仅支持公共的方法应用事务
*/
private final boolean publicMethodsOnly;
/**
* 事务注解的解析器
*/
private final Set<TransactionAnnotationParser> annotationParsers;
/**
* 创建一个默认的AnnotationTransactionAttributeSource,除了Spring的org.springframework.transaction.annotation.Transactional注解之外
* 还支持JTA 1.2的javax.transaction.Transactional事务注解以及EJB3的javax.ejb.TransactionAttribute事务注解
*
* 并且仅支持公共的方法应用于事务中
*/
public AnnotationTransactionAttributeSource() {
this(true);
}
/**
* @param publicMethodsOnly 是否支持只携带事务注解的公共方法(通常用于基于代理的AOP),还是受保护的私有方法(通常与AspectJ类编织一起使用)
*/
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
//设置属性
this.publicMethodsOnly = publicMethodsOnly;
//如果存在JTA 1.2的javax.transaction.Transactional事务注解或者EJB3的javax.ejb.TransactionAttribute事务注解
if (jta12Present || ejb3Present) {
//设置事务注解解析器集合
this.annotationParsers = new LinkedHashSet<>(4);
//添加SpringTransactionAnnotationParser解析器
//用于解析Spring自带的org.springframework.transaction.annotation.Transactional注解
this.annotationParsers.add(new SpringTransactionAnnotationParser());
//添加对应的外部事物注解的解析器
if (jta12Present) {
this.annotationParsers.add(new JtaTransactionAnnotationParser());
}
if (ejb3Present) {
this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
}
} else {
//如果没有其他的外部事务注解
//设置事务注解解析器集合,其中仅有一个SpringTransactionAnnotationParser解析器
//用于解析Spring自带的org.springframework.transaction.annotation.Transactional注解
this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
}
}
我们来看看AnnotationTransactionAttributeSource的isCandidateClass方法。
原理很简单,遍历注解解析器集合依次判断是否可以解析目标类型,只要有一个解析器能够解析,那么就算合格。
/**
* AnnotationTransactionAttributeSource的方法
*
* @param targetClass 目标类型
* @return true 表示属于候选class,false 表示不会继续进行方法匹配
*/
@Override
public boolean isCandidateClass(Class<?> targetClass) {
//遍历注解解析器集合
for (TransactionAnnotationParser parser : this.annotationParsers) {
//判断是否可以解析目标类型
if (parser.isCandidateClass(targetClass)) {
//只要有一个解析器能够解析,那么就算合格
return true;
}
}
return false;
}
我们简单看看SpringTransactionAnnotationParser
解析器,因为现在基本上都是使用Spring自带的注解了。
其内部调用了AnnotationUtils.isCandidateClass
方法。该方法的通用逻辑就是:如果任何一个注解的全路径名都不是以"java."开始,并且该Class全路径名以"start."开始或者Class的类型为Ordered.class,那么返回false,否则其他情况都返回true。因此,基本上普通class都会返回true,表示可以进行后续的方法校验。
/**
* SpringTransactionAnnotationParser的方法
*
* @param targetClass 目标类型
* @return 是否是候选class
*/
@Override
public boolean isCandidateClass(Class<?> targetClass) {
/*
* 确定给定的类是否是携带指定注解的候选者(在类型、方法或字段级别)。
*
* 如果任何一个注解的全路径名都不是以"java."开始,并且该Class全路径名以"start."开始或者Class的类型为Ordered.class,
* 那么返回false,否则其他情况都返回true。因此,基本上都会返回true
*/
return AnnotationUtils.isCandidateClass(targetClass, Transactional.class);
}
TransactionAttributeSourcePointcut实现了MethodMatcher接口,因此它自己就是一个方法匹配器。在匹配每一个方法的时候,将会调用MethodMatcher. matches方法,也就是它自己重写的matches方法。
/**
1. TransactionAttributeSourcePointcut的方法
2.
3. 通过委托AnnotationTransactionAttributeSource的getTransactionAttribute方法来判断该方法是否匹配
4. 5. @param method 需要匹配的方法
6. @param targetClass 实际目标类型
7. @return true 可以被代理,false不可以被代理
*/
@Override
public boolean matches(Method method, Class<?> targetClass) {
TransactionAttributeSource tas = getTransactionAttributeSource();
//如果TransactionAttributeSource不为null并且getTransactionAttribute方法返回null
//那么表示当前bean实例不会进行事务代理,否则表示可以进行事务代理
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
我们来看看AnnotationTransactionAttributeSource的getTransactionAttribute方法。该方法是父类AbstractFallbackTransactionAttributeSource实现的。
可以看到,该方法的逻辑也比较简单:
/*AbstractFallbackTransactionAttributeSource的相关属性*/
/**
* TransactionAttributes的缓存,key定位到目标类上的某个方法。
*/
private final Map<Object, TransactionAttribute> attributeCache = new ConcurrentHashMap<>(1024);
/**
* 缓存中保存的值常量,表示没有为该方法找到事务属性,但是我们也不需要再次查找。
*/
private static final TransactionAttribute NULL_TRANSACTION_ATTRIBUTE = new DefaultTransactionAttribute() {
@Override
public String toString() {
return "null";
}
};
/**
* AbstractFallbackTransactionAttributeSource的方法
*
* 确定此方法调用的事务属性。如果没有找到方法属性,则默认为类的事务属性。
*
* @param method 当前调用的方法(永不为空)
* @param targetClass 调用的目标类(可能是null)
* @return 此方法的TransactionAttribute,如果该方法不是事务性的,则为null
*/
@Override
@Nullable
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
//如果方法是属于Object,直接返回null,这些方法不会应用事务,比如Object的hashcode、equals……
if (method.getDeclaringClass() == Object.class) {
return null;
}
//获取方法和目标类的缓存key
Object cacheKey = getCacheKey(method, targetClass);
//尝试从缓存获取
TransactionAttribute cached = this.attributeCache.get(cacheKey);
//如果此前解析过该方法以及目标类,那么Value要么是指示没有事务属性,要么是一个实际的事务属性,一定不会为null
if (cached != null) {
//如果value指示没有事务属性,那么返回null
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
} else {
//否则直接返回此前解析的事务属性
return cached;
}
} else {
//到这里表示此前没有解析过该方法和目标类型
//那么根据当前方法和目标类型计算出TransactionAttribute
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// 如果为null
if (txAttr == null) {
//那么存入一个表示没有事务属性的固定值到缓存中,再次遇到时不再解析
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
} else {
//如果不为null,说明获取到了事务属性
//获取给定方法的全限定名,基本仅用于输出日志
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
//如果事务属性属于DefaultTransactionAttribute
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);
}
//返回txAttr,可能为null
return txAttr;
}
}
/**
1. AbstractFallbackTransactionAttributeSource的方法
2.
3. 确定给定方法和目标类的缓存key,即MethodClassKey,通过method和class来进行比较
*/
protected Object getCacheKey(Method method, @Nullable Class<?> targetClass) {
return new MethodClassKey(method, targetClass);
}
可以看到,这里使用了缓存的逻辑,非常的巧妙,另外,真正直接解析的逻辑位于computeTransactionAttribute方法中。
该方法用于计算给定方法和目标类型的事务属性,一般查找顺序为:执行的目标方法、对应的接口方法(如果有)、目标类、接口类(如果有),其中一个找到了就直接返回,不会继续查找。 具体逻辑如下:
/**
* AbstractFallbackTransactionAttributeSource的方法
*
* 计算事务属性的核心方法,但不缓存结果。getTransactionAttribute是这个方法的一个有效的缓存装饰器。
*/
@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
//默认不允许非公共方法进行事务代理,这里就是判断public方法的逻辑,但是可以通过allowPublicMethodsOnly方法修改
//如果是其他访问权限,比如default,那么获取其他AOP操作能够代理,但是事务不会生效
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
//获取最终要执行的目标方法,有可能参数方法表示的是一个接口的方法,我们需要找到实现类的方法
//通常情况下,参数方法就是最终执行的方法
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
//首先去找直接标记在方法上的事务注解并解析为事务属性
//如果方法上有就直接返回,不会再看类上的了事务注解了,这就是方法上的事务注解的优先级更高的原理
//findTransactionAttribute方法由子类实现
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
//如果方法上没有就查找目标类上的事务注解,有就直接返回
//findTransactionAttribute方法由子类实现
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
//到这里表示没有在目标方法或者类上找到事务注解,如果最终的目标方法和当前方法不一致,那么在当前方法中查找
//实际上很难走到这一步,在此前的查找中基本上就返回了
if (specificMethod != method) {
//我们会查找参数方法上的事务注解,如果找到了就返回
//findTransactionAttribute方法由子类实现
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
//如果还是没找到,那么最后一次尝试
//查找类上是否有事务注解,如果找到了就返回
//findTransactionAttribute方法由子类实现
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
//以上都找不到事务注解,那么将返回null,表示当前方法不会进行事务代理
return null;
}
/**
* 默认情况下,只有公共方法可以被设为事务性的。
*
* 子类AnnotationTransactionAttributeSource重写了该方法,将返回publicMethodsOnly的属性值
* 同样默认也是只有公共方法可以被设为事务性的
*/
@Override
protected boolean allowPublicMethodsOnly() {
return this.publicMethodsOnly;
}
最终查找事务属性的工作是通过findTransactionAttribute
方法来实现的。
findTransactionAttribute方法在查找方法上的注解的时候,会先查找目标方法本身的注解,然后才递归的向上会查找父级类对应方法上的注解,返回找到的第一个注解。
findTransactionAttribute方法在查找类上的注解的时候,会先查找目标类本身的注解,然后才递归的向上会查找父级类上的注解,返回找到的第一个注解。
该方法由子类AnnotationTransactionAttributeSource实现,在其实现中,可以看到,最终还是委托此前配置的TransactionAnnotationParser注解解析器的parseTransactionAnnotation
方法来执行解析。
和此前判断class一样,又是按顺序遍历设置的注解解析器集合,委托内部的解析器解析,找到一个就返回,不会应用后续的解析器,什么意思呢,如果一个方法使用了多种事务注解,仍然会按照解析器的顺序解析,最终只有一个注解会生效,默认头部解析器就是SpringTransactionAnnotationParser,支持Spring的@Transactional注解。
/**
* 子类AnnotationTransactionAttributeSource实现的方法
*
* @param method 当前要查找的方法
* @return 事务属性源,可能为null
*/
@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Method method) {
return determineTransactionAttribute(method);
}
/**
* 子类AnnotationTransactionAttributeSource实现的方法
*
* @param clazz 当前要查找的类
* @return 事务属性源,可能为null
*/
@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
return determineTransactionAttribute(clazz);
}
/**
1. 子类AnnotationTransactionAttributeSource的方法
2.
3. 确定给定方法或类的事务属性。
4. 该实现委托配置的TransactionAnnotationParser将已知的注解解析到Spring的元数据属性类中。如果不是事务性的,则返回null。
5.
6. 可以覆盖该方法,以支持携带事务元数据的自定义事务注解。
7. 8. @param element 带注解的方法或类
9. @return 配置的事务属性,如果没有找到,则为null
*/
@Nullable
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
//和此前判断class一样,又是按顺序遍历设置的注解解析器集合,委托内部的解析器解析
for (TransactionAnnotationParser parser : this.annotationParsers) {
//这次是调用解析器的parseTransactionAnnotation方法
TransactionAttribute attr = parser.parseTransactionAnnotation(element);
//找到一个就返回,不会应用后续的解析器
//什么意思呢,如果一个方法使用了多种事务注解,仍然会按照解析器的顺序解析,最终只有一个注解会生效
//默认头部解析器就是SpringTransactionAnnotationParser,支持Spring的@Transactional注解
if (attr != null) {
return attr;
}
}
return null;
}
最终会依次调用AnnotationTransactionAttributeSource的annotationParsers集中的TransactionAnnotationParser事务注解解析器的parseTransactionAnnotation方法,来解析不同的事务注解,并且封装为一个TransactionAnnotation返回。
我们主要看SpringTransactionAnnotationParser,它支持Spring的@Transactional注解。它的原理很简单:
子标签也会被解析为一个个的RuleBasedTransactionAttribute实例。/**
* SpringTransactionAnnotationParser的方法
*
* 解析方法或者类上的@Transactional注解并解析为一个TransactionAttribute返回
*
* @param element 方法或者类元数据
* @return TransactionAttribute,可能为null
*/
@Override
@Nullable
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
//查找方法或者类上的@Transactional注解,这里会递归的进行向上查找
//如果在当前方法/类上没找到,那么会继续在父类/接口的方法/类上查找,最终将使用找到的第一个注解数据
//这就是在接口方法或者接口上的事务注解也能生效的原因,但是它们的优先级更低
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
element, Transactional.class, false, false);
//如果找到了@Transactional注解
if (attributes != null) {
//解析注解属性,封装为一个TransactionAttribute并返回,实际类型为RuleBasedTransactionAttribute
return parseTransactionAnnotation(attributes);
} else {
//返回null
return null;
}
}
/**
* SpringTransactionAnnotationParser的方法
*
* 开放的方法,解析指定的注解为一个TransactionAttribute
*
* @param ann 注解
* @return TransactionAttribute
*/
public TransactionAttribute parseTransactionAnnotation(Transactional ann) {
return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false));
}
/**
* SpringTransactionAnnotationParser的方法
*
* 解析注解的各种属性,封装到一个RuleBasedTransactionAttribute对象中
*
* @param attributes 注解
* @return RuleBasedTransactionAttribute
*/
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
//最终会创建一个RuleBasedTransactionAttribute
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<>();
//rollbackFor在最前
for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
//rollbackForClassName在第二
for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
//noRollbackFor在第三
for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
//noRollbackForClassName在最后
for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
rbta.setRollbackRules(rollbackRules);
return rbta;
}
本次主要讲解了如何判断基于注解的声明式事物是否可以作用在某个类上。主要就是判断类/接口上、方法上是否有符合规则的事务注解,如果有,那么就可以被增强。默认情况下,基于注解的声明式事务仅支持public方法的增强,这里点是在computeTransactionAttribute源码中进行判断的。
@Transactional注解也是在判断时解析的
。在AutoProxyCreator的postProcessAfterInitialization方法判断当前bean是否可以被代理时,在内部的canApply方法中,在通过BeanFactoryTransactionAttributeSourceAdvisor通知器的TransactionAttributeSourcePointcut切入点的matches方法中进行解析的,该方法看起来是在调用AnnotationTransactionAttributeSource,但如果要精确到最终的解析者,那么就是AnnotationTransactionAttributeSource内部保存的SpringTransactionAnnotationParser这个解析器,而解析的结果也会被缓存到AbstractFallbackTransactionAttributeSource的attributeCache中,后续将直接使用。
基于注解的Spring声明式事务处理过程中,在BeanFactoryTransactionAttributeSourceAdvisor和TransactionInterceptor都配置了同一个TransactionAttributeSource
,因此,在上面,虽然是将结果缓存到BeanFactoryTransactionAttributeSourceAdvisor内部的TransactionAttributeSource中,但是由于它们指向同一个对象,那么TransactionInterceptor中的TransactionAttributeSource也能获取到缓存的数据,这样就相当于配置好了不同的方法对应的事务属性。这类似于此前的
标签解析时,配置的NameMatchTransactionAttributeSource,只不过它的规则是直接配置的
标签,而AnnotationTransactionAttributeSource的规则是后来运行时解析的各种事务注解组成的!
@Transactional注解的解析优先级是:目标方法的@Transactional注解、父类/接口方法的@Transactional注解、目标类的@Transactional注解、父类/接口的@Transactional注解。
@Transactional注解将被解析为一个RuleBasedTransactionAttribute并缓存到AbstractFallbackTransactionAttributeSource的attributeCache集合中。RuleBasedTransactionAttribute我们在此前基于XML的配置解析中就见过了,
子标签也会被解析为一个个的RuleBasedTransactionAttribute实例。
简要流程图为:
如果某个bean可以被事务增强,那么bean将会创建代理对象,并且BeanFactoryTransactionAttributeSourceAdvisor将会加入代理对象的通知器链中。在后续调用具体方法时,将会根据通知器链中的通知器解析为对应的Interceptor拦截器链,随后即可在目标方法的各个调用点通过责任链模式递归的执行各种AOP增强的逻辑,这其中自然包括BeanFactoryTransactionAttributeSourceAdvisor中的TransactionInterceptor拦截器,因此,下面我们将介绍TransactionInterceptor,它是真正为某个方法执行Spring声明式事务处理的地方,也是又一个重点!
相关文章:
https://spring.io/
Spring Framework 5.x 学习
Spring Framework 5.x 源码
如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!