事务声明原理

# EnableTransactionManagement注解

类似AOP原理 (opens new window)从注解EnableTransactionManagement入手

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

	//当选择代理模式AdviceMode.PROXY时  用来指定是否直接使用CGLIB代理 true:直接使用CGLIB创建子类代理,false: 实现接口的可以使用JDK动态代理
	boolean proxyTargetClass() default false;

	//切面模式  AdviceMode.PROXY:代理模式,本地调用会出现拦截失效(类方法调用自己的另一个方法),AdviceMode.ASPECTJ本地调用不会拦截时效
	AdviceMode mode() default AdviceMode.PROXY;

	//当有多个切面方法时,事务的切面方法最后执行
	int order() default Ordered.LOWEST_PRECEDENCE;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

@Import (opens new window)导入TransactionManagementConfigurationSelector UML类图 在加载BeanDefinition的时候会调用ImportSelector.selectImports(AnnotationMetadata)方法
TransactionManagementConfigurationSelectorselectImports(AdviceMode adviceMode)是一个重载方法,所以会先调到AdviceModeImportSelector.selectImports(AnnotationMetadata)

public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
    //获取AdviceModeImportSelector<A extends Annotation>的参数化类型 既A的类型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()));
	}
    //获取增强模式
	AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName());
    //调用留给之类实现的方法
	String[] imports = selectImports(adviceMode);
	if (imports == null) {
		throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode);
	}
	return imports;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

TransactionManagementConfigurationSelector.selectImports

protected String[] selectImports(AdviceMode adviceMode) {
	switch (adviceMode) {
		case PROXY:
			return new String[] {AutoProxyRegistrar.class.getName(),
					ProxyTransactionManagementConfiguration.class.getName()};
		case ASPECTJ:
			return new String[] {determineTransactionAspectClass()};
		default:
			return null;
	}
}
1
2
3
4
5
6
7
8
9
10
11

以代理模式为例,spring会对返回的AutoProxyRegistrarProxyTransactionManagementConfiguration继续执行Import解析。

# 事务自动代理框架

在处理AutoProxyRegistrar时,由于该类实现了ImportBeanDefinitionRegistrar接口,在解析BeanDefinition时会调用registerBeanDefinitions方法

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
	boolean candidateFound = false;
	Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
	for (String annType : annTypes) {
        //从元数据中获取属于EnableTransactionManagement的参数
		AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
		if (candidate == null) {
			continue;
		}
		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;
			if (mode == AdviceMode.PROXY) {
				AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
				if ((Boolean) proxyTargetClass) {
					AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
					return;
				}
			}
		}
	}
    //...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

AopConfigUtils.registerAutoProxyCreatorIfNecessary

public static BeanDefinition registerAutoProxyCreatorIfNecessary(
		BeanDefinitionRegistry registry, @Nullable Object source) {
	return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
1
2
3
4

注册一个自动代理类InfrastructureAdvisorAutoProxyCreator InfrastructureAdvisorAutoProxyCreator UML类图 这里对比一下 AOP原理 (opens new window)注册的BeanDefinition类型是AnnotationAwareAspectJAutoProxyCreator,继承关系大致相同,都是用来实现自动代理功能。

那么会不会有两套代理框架,导致功能重复呢?
答案在registerOrEscalateApcAsRequired方法中

private static BeanDefinition registerOrEscalateApcAsRequired(
		Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    //是否已经注册过org.springframework.aop.config.internalAutoProxyCreator的BeanDefinition
	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) {
				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);
    //注册的BeanDefinition类名为org.springframework.aop.config.internalAutoProxyCreator
	registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
	return beanDefinition;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

AopConfigUtils.findPriorityForClass

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);
	APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}
private static int findPriorityForClass(@Nullable String className) {
	for (int i = 0; i < APC_PRIORITY_LIST.size(); i++) {
		Class<?> clazz = APC_PRIORITY_LIST.get(i);
		if (clazz.getName().equals(className)) {
			return i;
		}
	}
	throw new IllegalArgumentException(
			"Class name [" + className + "] is not a known auto-proxy creator class");
} 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

优先级InfrastructureAdvisorAutoProxyCreator>AspectJAwareAdvisorAutoProxyCreator>AnnotationAwareAspectJAutoProxyCreator

# 事务自动代理的切面

在处理ProxyTransactionManagementConfiguration时,该类不是ImportSelector.class类型也不是ImportBeanDefinitionRegistrar类型,按配置类处理

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

    //org.springframework.transaction.config.internalTransactionAdvisor  通知Bean
	@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() {
        //这里使用的是针对注解类型的事务配置Bean
		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;
	}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@Configuration
public abstract class AbstractTransactionManagementConfiguration implements ImportAware {
	// ...

	//实现ImportAware 的接口方法 主要作用是拿到`@EnableTransactionManagement`的配置
	@Override
	public void setImportMetadata(AnnotationMetadata importMetadata) {
		this.enableTx = AnnotationAttributes.fromMap(
				importMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName(), false));
		if (this.enableTx == null) {
			throw new IllegalArgumentException("@EnableTransactionManagement is not present on importing class " + importMetadata.getClassName());
		}
	}
	//注入事务管理器
	@Autowired(required = false)
	void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
		if (CollectionUtils.isEmpty(configurers)) {
			return;
		}
		if (configurers.size() > 1) {
			throw new IllegalStateException("Only one TransactionManagementConfigurer may exist");
		}
		TransactionManagementConfigurer configurer = configurers.iterator().next();
		this.txManager = configurer.annotationDrivenTransactionManager();
	}

	//事务监听器
	@Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
		return new TransactionalEventListenerFactory();
	}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

可以看到通过导入ProxyTransactionManagementConfiguration,会添加ProxyTransactionManagementConfiguration,BeanFactoryTransactionAttributeSourceAdvisor,TransactionAttributeSource,TransactionInterceptor,TransactionalEventListenerFactory这些BeanDefinition

# 事务相关Bean实例化以及发挥作用的时机

  1. TransactionalEventListenerFactory 在通过注解加载BeanDefinition (opens new window)中提到Spring会向容器中添加EventListenerMethodProcessor,该Bean实现了BeanFactoryPostProcessor, 所以在容器刷新第五步invokeBeanFactoryPostProcessors时执行EventListenerMethodProcessor的后置处理
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	this.beanFactory = beanFactory;
	//获取EventListenerFactory类型的Bean
	Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
	List<EventListenerFactory> factories = new ArrayList<>(beans.values());
	AnnotationAwareOrderComparator.sort(factories);
	this.eventListenerFactories = factories;
}
1
2
3
4
5
6
7
8

TransactionalEventListenerFactory实现了EventListenerFactory,在这里注册到Bean容器。

  1. InfrastructureAdvisorAutoProxyCreator 该类实现了BeanPostProcessor,在容器刷新的第六步registerBeanPostProcessors注册到Bean容器。
    在后续的Bean创建过程中,该类的后置处理方法被执行。

  2. TransactionAttributeSource,TransactionInterceptor 在其他Bean创建时,AOP框架开始发挥作用。
    在Bean初始化后进行后置增强 (opens new window),获取切面通知,进入BeanFactoryTransactionAttributeSourceAdvisor的创建流程。 由于该Bean的创建方法需要入参TransactionAttributeSourceTransactionInterceptor,会先实例化这两个Bean

public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
		implements Serializable {
	// ...

	public AnnotationTransactionAttributeSource() {
		this(true);
	}
	public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
		this.publicMethodsOnly = publicMethodsOnly;
		//if...
		else {
			this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
		}
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  1. BeanFactoryTransactionAttributeSourceAdvisor 获取切面通知时实例化改Bean
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {

	@Nullable
	private TransactionAttributeSource transactionAttributeSource;

	private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
		@Override
		@Nullable
		protected TransactionAttributeSource getTransactionAttributeSource() {
			return transactionAttributeSource;
		}
	};
}
1
2
3
4
5
6
7
8
9
10
11
12
13

BeanFactoryTransactionAttributeSourceAdvisor

内置切入点TransactionAttributeSourcePointcut

abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {

	protected TransactionAttributeSourcePointcut() {
		setClassFilter(new TransactionAttributeSourceClassFilter());
	}

	@Override
	public boolean matches(Method method, Class<?> targetClass) {
		TransactionAttributeSource tas = getTransactionAttributeSource();
		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
	}
}
1
2
3
4
5
6
7
8
9
10
11
12

在获取所有的通知方法后,会校验当前创建的Bean是否需要代理 AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply

protected List<Advisor> findAdvisorsThatCanApply(
		List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

	ProxyCreationContext.setCurrentProxiedBeanName(beanName);
	try {
		return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
	}
	finally {
		ProxyCreationContext.setCurrentProxiedBeanName(null);
	}
}
1
2
3
4
5
6
7
8
9
10
11

最终到调用方法AopUtils#canApply

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
	Assert.notNull(pc, "Pointcut must not be null");
	//先校验当前类是否匹配切入点
	if (!pc.getClassFilter().matches(targetClass)) {
		return false;
	}
	//切入点的匹配方法
	MethodMatcher methodMatcher = pc.getMethodMatcher();
	if (methodMatcher == MethodMatcher.TRUE) {
		// No need to iterate the methods if we're matching any method anyway...
		return true;
	}

	IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
	if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
		introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
	}

	Set<Class<?>> classes = new LinkedHashSet<>();
	if (!Proxy.isProxyClass(targetClass)) {
		classes.add(ClassUtils.getUserClass(targetClass));
	}
	classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

	for (Class<?> clazz : classes) {
		//获取所有类方法,包括超类的方法
		Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
		//检测类方法是否匹配
		for (Method method : methods) {
			if (introductionAwareMethodMatcher != null ?
					introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
					methodMatcher.matches(method, targetClass)) {
				return true;
			}
		}
	}

	return false;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# 切入点与类的校验

TransactionAttributeSourcePointcut内置classFilterTransactionAttributeSourceClassFilter,是TransactionAttributeSourcePointcut的内部类

private class TransactionAttributeSourceClassFilter implements ClassFilter {

	@Override
	public boolean matches(Class<?> clazz) {
		if (TransactionalProxy.class.isAssignableFrom(clazz) ||
				TransactionManager.class.isAssignableFrom(clazz) ||
				PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
			return false;
		}
		//因为是内部类,调用的是TransactionAttributeSourcePointcut.getTransactionAttributeSource方法,
		//获取的是BeanFactoryTransactionAttributeSourceAdvisor.transactionAttributeSource 即AnnotationTransactionAttributeSource
		TransactionAttributeSource tas = getTransactionAttributeSource();
		return (tas == null || tas.isCandidateClass(clazz));
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

AnnotationTransactionAttributeSource.isCandidateClass

public boolean isCandidateClass(Class<?> targetClass) {
	for (TransactionAnnotationParser parser : this.annotationParsers) {
		if (parser.isCandidateClass(targetClass)) {
			return true;
		}
	}
	return false;
}
1
2
3
4
5
6
7
8

在创建TransactionAttributeSource时已经从构造方法中可以看出annotationParsers中存放的是SpringTransactionAnnotationParser SpringTransactionAnnotationParser.isCandidateClass

public boolean isCandidateClass(Class<?> targetClass) {
	return AnnotationUtils.isCandidateClass(targetClass, Transactional.class);
}
1
2
3

AnnotationUtils.isCandidateClass用于判断指定类能否承载指定注解的候选类

public static boolean isCandidateClass(Class<?> clazz, String annotationName) {
	//java.开头的注解可以用于任何类
	if (annotationName.startsWith("java.")) {
		return true;
	}
	//这个方法是return (type.getName().startsWith("java.") || type == Ordered.class);
	//即JDK中的类、Ordered类不能承载注解
	if (AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) {
		return false;
	}
	return true;
}
1
2
3
4
5
6
7
8
9
10
11
12

所以能承载@Transactional而不仅仅是使用该注解,切入点对类的校验都是通过的

# 切入点与类方法的匹配

TransactionAttributeSourcePointcut间接实现MethodMatcher接口 TransactionAttributeSourcePointcut 其实现的getMethodMatcher方法是返回自身,然后调用自己的matches方法

public boolean matches(Method method, Class<?> targetClass) {
	TransactionAttributeSource tas = getTransactionAttributeSource();
	return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
1
2
3
4

最终调到父类方法AbstractFallbackTransactionAttributeSource#getTransactionAttribute
该方法用于获取事务配置

public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
	if (method.getDeclaringClass() == Object.class) {
		return null;
	}

	//先从缓存中查,这部分省略...
	//需要注意的是,没有事务配置的方法也需要缓存,和未处理过的方法作区分
	else {
		//获取事务配置
		TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
		
		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);
			}
			this.attributeCache.put(cacheKey, txAttr);
		}
		return txAttr;
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
	// 默认公共方法才生效
	if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
		return null;
	}

	//因为上文查的是叶类与超类的所有方法,当处理超类的方法时,需要找到对应目标类的具体方法
	Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

	// 先从目标类的方法中找
	TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
	if (txAttr != null) {
		return txAttr;
	}

	// 再看目标类上是否有事务配置
	txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
	if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
		return txAttr;
	}

	if (specificMethod != method) {
		// 如果方法是超类的方法,看看超类方法上是否有事务配置
		txAttr = findTransactionAttribute(method);
		if (txAttr != null) {
			return txAttr;
		}
		// 再看看超类上是否有事务配置
		txAttr = findTransactionAttribute(method.getDeclaringClass());
		if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
			return txAttr;
		}
	}

	return null;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

AopUtils.getMostSpecificMethod的思路是根据方法签名(这里指的是编译器规定的方法签名,Java的方法签名是方法名和参数,编译器的方法签名还包括返回值),获取子类对应超类的方法,然后检查是否是桥接方法,如果是桥接方法,返回桥接方法指向的方法。关于桥接方法暂时看的是这篇博客 (opens new window),以后再做整理。

# 获取事务配置

findTransactionAttribute方法调用到AnnotationTransactionAttributeSource#determineTransactionAttribute方法

protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
	for (TransactionAnnotationParser parser : this.annotationParsers) {
		TransactionAttribute attr = parser.parseTransactionAnnotation(element);
		if (attr != null) {
			return attr;
		}
	}
	return null;
}
1
2
3
4
5
6
7
8
9

上文提到过这个TransactionAnnotationParser就是SpringTransactionAnnotationParser

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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

到这里即完成了获取方法的事务属性配置的功能。有该配置的方法的类既是需要代理的类。

上次更新: 2023/04/09, 16:34:32
最近更新
01
go-admin-ui项目仿写练手1-登录页
06-29
02
maven依赖问题
06-17
03
JVM相关命令
02-21
更多文章>