Skip to content

Commit 715e8c9

Browse files
committed
Align TransactionManagementConfigurer support in TCF with production
This commit picks up where 613bd3b left off by ensuring that a transaction manager configured via the TransactionManagementConfigurer API takes precedence over any transaction manager configured as a bean in the ApplicationContext unless @transactional is configured with a qualifier for the explicit transaction manager to use in tests. Closes gh-24869
1 parent 65acda8 commit 715e8c9

File tree

3 files changed

+153
-7
lines changed

3 files changed

+153
-7
lines changed

spring-test/src/main/java/org/springframework/test/context/transaction/TestContextTransactionUtils.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -183,13 +183,6 @@ public static PlatformTransactionManager retrieveTransactionManager(TestContext
183183
if (bf instanceof ListableBeanFactory) {
184184
ListableBeanFactory lbf = (ListableBeanFactory) bf;
185185

186-
// Look up single bean by type
187-
Map<String, PlatformTransactionManager> txMgrs =
188-
BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, PlatformTransactionManager.class);
189-
if (txMgrs.size() == 1) {
190-
return txMgrs.values().iterator().next();
191-
}
192-
193186
// Look up single TransactionManagementConfigurer
194187
Map<String, TransactionManagementConfigurer> configurers =
195188
BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, TransactionManagementConfigurer.class);
@@ -203,6 +196,13 @@ public static PlatformTransactionManager retrieveTransactionManager(TestContext
203196
return (PlatformTransactionManager) tm;
204197
}
205198

199+
// Look up single bean by type
200+
Map<String, PlatformTransactionManager> txMgrs =
201+
BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, PlatformTransactionManager.class);
202+
if (txMgrs.size() == 1) {
203+
return txMgrs.values().iterator().next();
204+
}
205+
206206
try {
207207
// Look up single bean by type, with support for 'primary' beans
208208
return bf.getBean(PlatformTransactionManager.class);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright 2002-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.test.context.transaction.manager;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import org.springframework.beans.factory.annotation.Autowired;
22+
import org.springframework.context.annotation.Bean;
23+
import org.springframework.context.annotation.Configuration;
24+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
25+
import org.springframework.test.context.transaction.AfterTransaction;
26+
import org.springframework.transaction.TransactionManager;
27+
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
28+
import org.springframework.transaction.annotation.Transactional;
29+
import org.springframework.transaction.testfixture.CallCountingTransactionManager;
30+
31+
import static org.assertj.core.api.Assertions.assertThat;
32+
33+
/**
34+
* Integration test that verifies the behavior for transaction manager lookups
35+
* when only one transaction manager is configured as a bean in the application
36+
* context and a non-bean transaction manager is configured via the
37+
* {@link TransactionManagementConfigurer} API.
38+
*
39+
* @author Sam Brannen
40+
* @since 5.3
41+
*/
42+
@SpringJUnitConfig
43+
@Transactional
44+
class LookUpTxMgrViaTransactionManagementConfigurerWithSingleTxMgrBeanTests {
45+
46+
@Autowired
47+
CallCountingTransactionManager txManager;
48+
49+
@Autowired
50+
Config config;
51+
52+
53+
@Test
54+
void transactionalTest() {
55+
assertThat(txManager.begun).isEqualTo(0);
56+
assertThat(txManager.inflight).isEqualTo(0);
57+
assertThat(txManager.commits).isEqualTo(0);
58+
assertThat(txManager.rollbacks).isEqualTo(0);
59+
60+
CallCountingTransactionManager annotationDriven = config.annotationDriven;
61+
assertThat(annotationDriven.begun).isEqualTo(1);
62+
assertThat(annotationDriven.inflight).isEqualTo(1);
63+
assertThat(annotationDriven.commits).isEqualTo(0);
64+
assertThat(annotationDriven.rollbacks).isEqualTo(0);
65+
}
66+
67+
@AfterTransaction
68+
void afterTransaction() {
69+
assertThat(txManager.begun).isEqualTo(0);
70+
assertThat(txManager.inflight).isEqualTo(0);
71+
assertThat(txManager.commits).isEqualTo(0);
72+
assertThat(txManager.rollbacks).isEqualTo(0);
73+
74+
CallCountingTransactionManager annotationDriven = config.annotationDriven;
75+
assertThat(annotationDriven.begun).isEqualTo(1);
76+
assertThat(annotationDriven.inflight).isEqualTo(0);
77+
assertThat(annotationDriven.commits).isEqualTo(0);
78+
assertThat(annotationDriven.rollbacks).isEqualTo(1);
79+
}
80+
81+
82+
@Configuration
83+
static class Config implements TransactionManagementConfigurer {
84+
85+
final CallCountingTransactionManager annotationDriven = new CallCountingTransactionManager();
86+
87+
@Bean
88+
TransactionManager txManager() {
89+
return new CallCountingTransactionManager();
90+
}
91+
92+
@Override
93+
public TransactionManager annotationDrivenTransactionManager() {
94+
return annotationDriven;
95+
}
96+
97+
}
98+
99+
}

spring-tx/src/test/java/org/springframework/transaction/annotation/EnableTransactionManagementTests.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,29 @@ public void txManagerIsResolvedCorrectlyWithTxMgmtConfigurerAndPrimaryPresent()
168168
ctx.close();
169169
}
170170

171+
@Test
172+
public void txManagerIsResolvedCorrectlyWithSingleTxManagerBeanAndTxMgmtConfigurer() {
173+
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
174+
EnableTxConfig.class, SingleTxManagerBeanAndTxMgmtConfigurerConfig.class);
175+
assertThat(ctx.getBeansOfType(TransactionManager.class)).hasSize(1);
176+
TransactionalTestBean bean = ctx.getBean(TransactionalTestBean.class);
177+
CallCountingTransactionManager txManager = ctx.getBean(CallCountingTransactionManager.class);
178+
SingleTxManagerBeanAndTxMgmtConfigurerConfig config = ctx.getBean(SingleTxManagerBeanAndTxMgmtConfigurerConfig.class);
179+
CallCountingTransactionManager annotationDriven = config.annotationDriven;
180+
181+
// invoke a transactional method, causing the PlatformTransactionManager bean to be resolved.
182+
bean.findAllFoos();
183+
184+
assertThat(txManager.begun).isEqualTo(0);
185+
assertThat(txManager.commits).isEqualTo(0);
186+
assertThat(txManager.rollbacks).isEqualTo(0);
187+
assertThat(annotationDriven.begun).isEqualTo(1);
188+
assertThat(annotationDriven.commits).isEqualTo(1);
189+
assertThat(annotationDriven.rollbacks).isEqualTo(0);
190+
191+
ctx.close();
192+
}
193+
171194
/**
172195
* A cheap test just to prove that in ASPECTJ mode, the AnnotationTransactionAspect does indeed
173196
* get loaded -- or in this case, attempted to be loaded at which point the test fails.
@@ -384,6 +407,30 @@ public PlatformTransactionManager annotationDrivenTransactionManager() {
384407
}
385408

386409

410+
@Configuration
411+
static class SingleTxManagerBeanAndTxMgmtConfigurerConfig implements TransactionManagementConfigurer {
412+
413+
final CallCountingTransactionManager annotationDriven = new CallCountingTransactionManager();
414+
415+
@Bean
416+
public TransactionalTestBean testBean() {
417+
return new TransactionalTestBean();
418+
}
419+
420+
@Bean
421+
public PlatformTransactionManager txManager() {
422+
return new CallCountingTransactionManager();
423+
}
424+
425+
// The transaction manager returned from this method is intentionally not
426+
// registered as a bean in the ApplicationContext.
427+
@Override
428+
public PlatformTransactionManager annotationDrivenTransactionManager() {
429+
return annotationDriven;
430+
}
431+
}
432+
433+
387434
@Configuration
388435
@EnableTransactionManagement
389436
static class Spr11915Config {

0 commit comments

Comments
 (0)