Support TransactionManagementConfigurer in the TCF
Currently the Spring TestContext Framework looks up a PlatformTransactionManager bean named "transactionManager". The exact name of the bean can be overridden via @TransactionConfiguration or @Transactional; however, the bean will always be looked up 'by name'. The TransactionManagementConfigurer interface that was introduced in Spring 3.1 provides a programmatic approach to specifying the PlatformTransactionManager bean to be used for annotation-driven transaction management, and that bean is not required to be named "transactionManager". However, as of Spring 3.1.2, using the TransactionManagementConfigurer on a @Configuration class has no effect on how the TestContext framework looks up the transaction manager. Consequently, if an explicit name or qualifier has not been specified, the bean must be named "transactionManager" in order for a transactional integration test to work. This commit addresses this issue by refactoring the TransactionalTestExecutionListener so that it looks up and delegates to a single TransactionManagementConfigurer as part of the algorithm for determining the transaction manager. Issue: SPR-9604
This commit is contained in:
@@ -40,12 +40,19 @@ public @interface TransactionConfiguration {
|
||||
|
||||
/**
|
||||
* The bean name of the {@link org.springframework.transaction.PlatformTransactionManager
|
||||
* PlatformTransactionManager} that is to be used to drive transactions.
|
||||
* PlatformTransactionManager} that should be used to drive transactions.
|
||||
*
|
||||
* <p>This attribute is not required and only needs to be specified explicitly
|
||||
* if there are multiple beans of type {@code PlatformTransactionManager} in
|
||||
* the test's {@code ApplicationContext} and the bean name of the desired
|
||||
* {@code PlatformTransactionManager} is not "transactionManager".
|
||||
* <p>This attribute is not required and only needs to be declared if there
|
||||
* are multiple beans of type {@code PlatformTransactionManager} in the test's
|
||||
* {@code ApplicationContext} <em>and</em> if one of the following is true.
|
||||
* <ul>
|
||||
* <li>the bean name of the desired {@code PlatformTransactionManager} is not
|
||||
* "transactionManager"</li>
|
||||
* <li>{@link org.springframework.transaction.annotation.TransactionManagementConfigurer
|
||||
* TransactionManagementConfigurer} was not implemented to specify which
|
||||
* {@code PlatformTransactionManager} bean should be used for annotation-driven
|
||||
* transaction management
|
||||
* </ul>
|
||||
*
|
||||
* <p><b>NOTE:</b> The XML {@code <tx:annotation-driven>} element also refers
|
||||
* to a bean named "transactionManager" by default. If you are using both
|
||||
|
||||
@@ -43,6 +43,7 @@ import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.TransactionException;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
|
||||
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
|
||||
import org.springframework.transaction.interceptor.DelegatingTransactionAttribute;
|
||||
import org.springframework.transaction.interceptor.TransactionAttribute;
|
||||
import org.springframework.transaction.interceptor.TransactionAttributeSource;
|
||||
@@ -68,11 +69,15 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* <p>Transactional commit and rollback behavior can be configured via the
|
||||
* class-level {@link TransactionConfiguration @TransactionConfiguration} and
|
||||
* method-level {@link Rollback @Rollback} annotations. In case there are multiple
|
||||
* instances of {@code PlatformTransactionManager} within the test's
|
||||
* {@code ApplicationContext}, {@code @TransactionConfiguration} supports
|
||||
* configuring the bean name of the {@code PlatformTransactionManager} that is
|
||||
* to be used to drive transactions.
|
||||
* method-level {@link Rollback @Rollback} annotations.
|
||||
*
|
||||
* <p>In case there are multiple instances of {@code PlatformTransactionManager}
|
||||
* within the test's {@code ApplicationContext}, @{@code TransactionConfiguration}
|
||||
* supports configuring the bean name of the {@code PlatformTransactionManager}
|
||||
* that should be used to drive transactions. Alternatively,
|
||||
* {@link TransactionManagementConfigurer} can be implemented in an
|
||||
* {@link org.springframework.context.annotation.Configuration @Configuration}
|
||||
* class.
|
||||
*
|
||||
* <p>When executing transactional tests, it is sometimes useful to be able to
|
||||
* execute certain <em>set up</em> or <em>tear down</em> code outside of a
|
||||
@@ -349,13 +354,25 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
||||
return bf.getBean(tmName, PlatformTransactionManager.class);
|
||||
}
|
||||
|
||||
// look up single bean by type
|
||||
if (bf instanceof ListableBeanFactory) {
|
||||
ListableBeanFactory lbf = (ListableBeanFactory) bf;
|
||||
Map<String, PlatformTransactionManager> beansOfType = BeanFactoryUtils.beansOfTypeIncludingAncestors(
|
||||
|
||||
// look up single bean by type
|
||||
Map<String, PlatformTransactionManager> txMgrs = BeanFactoryUtils.beansOfTypeIncludingAncestors(
|
||||
lbf, PlatformTransactionManager.class);
|
||||
if (beansOfType.size() == 1) {
|
||||
return beansOfType.values().iterator().next();
|
||||
if (txMgrs.size() == 1) {
|
||||
return txMgrs.values().iterator().next();
|
||||
}
|
||||
|
||||
// look up single TransactionManagementConfigurer
|
||||
Map<String, TransactionManagementConfigurer> configurers = BeanFactoryUtils.beansOfTypeIncludingAncestors(
|
||||
lbf, TransactionManagementConfigurer.class);
|
||||
if (configurers.size() > 1) {
|
||||
throw new IllegalStateException(
|
||||
"Only one TransactionManagementConfigurer may exist in the ApplicationContext");
|
||||
}
|
||||
if (configurers.size() == 1) {
|
||||
return configurers.values().iterator().next().annotationDrivenTransactionManager();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user