Consider type-level qualifier annotations for transaction manager selection
Closes gh-24291
This commit is contained in:
@@ -139,6 +139,14 @@ public @interface Transactional {
|
||||
* qualifier value (or the bean name) of a specific
|
||||
* {@link org.springframework.transaction.TransactionManager TransactionManager}
|
||||
* bean definition.
|
||||
* <p>Alternatively, as of 6.2, a type-level bean qualifier annotation with a
|
||||
* {@link org.springframework.beans.factory.annotation.Qualifier#value() qualifier value}
|
||||
* is also taken into account. If it matches the qualifier value (or bean name)
|
||||
* of a specific transaction manager, that transaction manager is going to be used
|
||||
* for transaction definitions without a specific qualifier on this attribute here.
|
||||
* Such a type-level qualifier can be declared on the concrete class, applying
|
||||
* to transaction definitions from a base class as well, effectively overriding
|
||||
* the default transaction manager choice for any unqualified base class methods.
|
||||
* @since 4.2
|
||||
* @see #value
|
||||
* @see org.springframework.transaction.PlatformTransactionManager
|
||||
|
||||
@@ -35,6 +35,7 @@ import reactor.core.publisher.Mono;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
|
||||
import org.springframework.core.CoroutinesUtils;
|
||||
import org.springframework.core.KotlinDetector;
|
||||
@@ -349,7 +350,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
|
||||
// If the transaction attribute is null, the method is non-transactional.
|
||||
TransactionAttributeSource tas = getTransactionAttributeSource();
|
||||
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
|
||||
final TransactionManager tm = determineTransactionManager(txAttr);
|
||||
final TransactionManager tm = determineTransactionManager(txAttr, targetClass);
|
||||
|
||||
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager rtm) {
|
||||
boolean isSuspendingFunction = KotlinDetector.isSuspendingFunction(method);
|
||||
@@ -499,9 +500,19 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
|
||||
|
||||
/**
|
||||
* Determine the specific transaction manager to use for the given transaction.
|
||||
* @param txAttr the current transaction attribute
|
||||
* @param targetClass the target class that the attribute has been declared on
|
||||
* @since 6.2
|
||||
*/
|
||||
@Nullable
|
||||
protected TransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
|
||||
protected TransactionManager determineTransactionManager(
|
||||
@Nullable TransactionAttribute txAttr, @Nullable Class<?> targetClass) {
|
||||
|
||||
TransactionManager tm = determineTransactionManager(txAttr);
|
||||
if (tm != null) {
|
||||
return tm;
|
||||
}
|
||||
|
||||
// Do not attempt to lookup tx manager if no tx attributes are set
|
||||
if (txAttr == null || this.beanFactory == null) {
|
||||
return getTransactionManager();
|
||||
@@ -511,7 +522,20 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
|
||||
if (StringUtils.hasText(qualifier)) {
|
||||
return determineQualifiedTransactionManager(this.beanFactory, qualifier);
|
||||
}
|
||||
else if (StringUtils.hasText(this.transactionManagerBeanName)) {
|
||||
else if (targetClass != null) {
|
||||
// Consider type-level qualifier annotations for transaction manager selection
|
||||
String typeQualifier = BeanFactoryAnnotationUtils.getQualifierValue(targetClass);
|
||||
if (StringUtils.hasText(typeQualifier)) {
|
||||
try {
|
||||
return determineQualifiedTransactionManager(this.beanFactory, typeQualifier);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
// Consider type qualifier as optional, proceed with regular resolution below.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(this.transactionManagerBeanName)) {
|
||||
return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
|
||||
}
|
||||
else {
|
||||
@@ -528,6 +552,16 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the specific transaction manager to use for the given transaction.
|
||||
* @deprecated as of 6.2, in favor of {@link #determineTransactionManager(TransactionAttribute, Class)}
|
||||
*/
|
||||
@Deprecated
|
||||
@Nullable
|
||||
protected TransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private TransactionManager determineQualifiedTransactionManager(BeanFactory beanFactory, String qualifier) {
|
||||
TransactionManager txManager = this.transactionManagerCache.get(qualifier);
|
||||
if (txManager == null) {
|
||||
@@ -538,7 +572,6 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init
|
||||
return txManager;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private PlatformTransactionManager asPlatformTransactionManager(@Nullable Object transactionManager) {
|
||||
if (transactionManager == null) {
|
||||
|
||||
Reference in New Issue
Block a user