From 085091dbe3423ce3d7436ac07af5259e67c0cc3e Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 25 Aug 2020 15:29:40 +0200 Subject: [PATCH] Adapt auto-configurations to back-off in presence of TransactionManager Previous to this commit, an auto-configuration would create a PlatformTransactionManager if none is present and others conditions are met. Spring Framework now has the notion of TransactionManager, a parent interface that gathers both PlatformTransactionManager and ReactiveTransactionManager. Spring Boot should not be in a situation where both managers are defined out-of-the-box. This commit makes sure to back-off if any TransactionManager is available. Closes gh-22851 --- ...SourceTransactionManagerAutoConfiguration.java | 8 ++++---- .../orm/jpa/JpaBaseConfiguration.java | 5 +++-- .../transaction/jta/AtomikosJtaConfiguration.java | 5 ++--- .../transaction/jta/BitronixJtaConfiguration.java | 3 +-- .../transaction/jta/JndiJtaConfiguration.java | 5 ++--- ...eTransactionManagerAutoConfigurationTests.java | 15 +++++++-------- .../jpa/AbstractJpaAutoConfigurationTests.java | 12 +++++++----- .../jta/JtaAutoConfigurationTests.java | 7 +++---- 8 files changed, 29 insertions(+), 31 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceTransactionManagerAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceTransactionManagerAutoConfiguration.java index 1664c622f6..63a3c598f6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceTransactionManagerAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceTransactionManagerAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +31,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DataSourceTransactionManager; -import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionManager; /** * {@link EnableAutoConfiguration Auto-configuration} for @@ -44,7 +44,7 @@ import org.springframework.transaction.PlatformTransactionManager; * @since 1.0.0 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnClass({ JdbcTemplate.class, PlatformTransactionManager.class }) +@ConditionalOnClass({ JdbcTemplate.class, TransactionManager.class }) @AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE) @EnableConfigurationProperties(DataSourceProperties.class) public class DataSourceTransactionManagerAutoConfiguration { @@ -54,7 +54,7 @@ public class DataSourceTransactionManagerAutoConfiguration { static class DataSourceTransactionManagerConfiguration { @Bean - @ConditionalOnMissingBean(PlatformTransactionManager.class) + @ConditionalOnMissingBean(TransactionManager.class) DataSourceTransactionManager transactionManager(DataSource dataSource, ObjectProvider transactionManagerCustomizers) { DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java index 4f9400ea31..836d61a386 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,6 +54,7 @@ import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter; import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor; import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter; import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionManager; import org.springframework.transaction.jta.JtaTransactionManager; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -92,7 +93,7 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware { } @Bean - @ConditionalOnMissingBean + @ConditionalOnMissingBean(TransactionManager.class) public PlatformTransactionManager transactionManager( ObjectProvider transactionManagerCustomizers) { JpaTransactionManager transactionManager = new JpaTransactionManager(); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/jta/AtomikosJtaConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/jta/AtomikosJtaConfiguration.java index abd3cd7084..393494c0a2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/jta/AtomikosJtaConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/jta/AtomikosJtaConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,7 +41,6 @@ import org.springframework.boot.jta.atomikos.AtomikosXADataSourceWrapper; import org.springframework.boot.system.ApplicationHome; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.jta.JtaTransactionManager; import org.springframework.util.StringUtils; @@ -57,7 +56,7 @@ import org.springframework.util.StringUtils; @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties({ AtomikosProperties.class, JtaProperties.class }) @ConditionalOnClass({ JtaTransactionManager.class, UserTransactionManager.class }) -@ConditionalOnMissingBean(PlatformTransactionManager.class) +@ConditionalOnMissingBean(org.springframework.transaction.TransactionManager.class) class AtomikosJtaConfiguration { @Bean(initMethod = "init", destroyMethod = "shutdownWait") diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/jta/BitronixJtaConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/jta/BitronixJtaConfiguration.java index 45aa9a4348..8ed2489aff 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/jta/BitronixJtaConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/jta/BitronixJtaConfiguration.java @@ -37,7 +37,6 @@ import org.springframework.boot.jms.XAConnectionFactoryWrapper; import org.springframework.boot.system.ApplicationHome; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.jta.JtaTransactionManager; import org.springframework.util.StringUtils; @@ -54,7 +53,7 @@ import org.springframework.util.StringUtils; @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(JtaProperties.class) @ConditionalOnClass({ JtaTransactionManager.class, BitronixContext.class }) -@ConditionalOnMissingBean(PlatformTransactionManager.class) +@ConditionalOnMissingBean(org.springframework.transaction.TransactionManager.class) class BitronixJtaConfiguration { @Bean diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/jta/JndiJtaConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/jta/JndiJtaConfiguration.java index 2bee60e2b5..cc9f6325a8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/jta/JndiJtaConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/jta/JndiJtaConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.config.JtaTransactionManagerFactoryBean; import org.springframework.transaction.jta.JtaTransactionManager; @@ -38,7 +37,7 @@ import org.springframework.transaction.jta.JtaTransactionManager; @ConditionalOnClass(JtaTransactionManager.class) @ConditionalOnJndi({ JtaTransactionManager.DEFAULT_USER_TRANSACTION_NAME, "java:comp/TransactionManager", "java:appserver/TransactionManager", "java:pm/TransactionManager", "java:/TransactionManager" }) -@ConditionalOnMissingBean(PlatformTransactionManager.class) +@ConditionalOnMissingBean(org.springframework.transaction.TransactionManager.class) class JndiJtaConfiguration { @Bean diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceTransactionManagerAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceTransactionManagerAutoConfigurationTests.java index a1f3242e36..26fc979ff3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceTransactionManagerAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceTransactionManagerAutoConfigurationTests.java @@ -26,7 +26,7 @@ import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.jdbc.datasource.DataSourceTransactionManager; -import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionManager; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -54,7 +54,7 @@ class DataSourceTransactionManagerAutoConfigurationTests { void transactionManagerWithExistingDataSourceIsConfigured() { this.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class)) .run((context) -> { - assertThat(context).hasSingleBean(PlatformTransactionManager.class) + assertThat(context).hasSingleBean(TransactionManager.class) .hasSingleBean(DataSourceTransactionManager.class); assertThat(context.getBean(DataSourceTransactionManager.class).getDataSource()) .isSameAs(context.getBean(DataSource.class)); @@ -67,7 +67,7 @@ class DataSourceTransactionManagerAutoConfigurationTests { .withPropertyValues("spring.transaction.default-timeout=1m", "spring.transaction.rollback-on-commit-failure=true") .run((context) -> { - assertThat(context).hasSingleBean(PlatformTransactionManager.class) + assertThat(context).hasSingleBean(TransactionManager.class) .hasSingleBean(DataSourceTransactionManager.class); DataSourceTransactionManager transactionManager = context .getBean(DataSourceTransactionManager.class); @@ -79,22 +79,21 @@ class DataSourceTransactionManagerAutoConfigurationTests { @Test void transactionManagerWithExistingTransactionManagerIsNotOverridden() { this.contextRunner - .withBean("myTransactionManager", PlatformTransactionManager.class, - () -> mock(PlatformTransactionManager.class)) - .run((context) -> assertThat(context).hasSingleBean(PlatformTransactionManager.class) + .withBean("myTransactionManager", TransactionManager.class, () -> mock(TransactionManager.class)) + .run((context) -> assertThat(context).hasSingleBean(TransactionManager.class) .hasBean("myTransactionManager")); } @Test void transactionWithMultipleDataSourcesIsNotConfigured() { this.contextRunner.withUserConfiguration(MultiDataSourceConfiguration.class) - .run((context) -> assertThat(context).doesNotHaveBean(PlatformTransactionManager.class)); + .run((context) -> assertThat(context).doesNotHaveBean(TransactionManager.class)); } @Test void transactionWithMultipleDataSourcesAndPrimaryCandidateIsConfigured() { this.contextRunner.withUserConfiguration(MultiDataSourceUsingPrimaryConfiguration.class).run((context) -> { - assertThat(context).hasSingleBean(PlatformTransactionManager.class) + assertThat(context).hasSingleBean(TransactionManager.class) .hasSingleBean(DataSourceTransactionManager.class); assertThat(context.getBean(DataSourceTransactionManager.class).getDataSource()) .isSameAs(context.getBean("test1DataSource")); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/AbstractJpaAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/AbstractJpaAutoConfigurationTests.java index c061ec3392..2507d82a95 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/AbstractJpaAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/AbstractJpaAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,6 +49,7 @@ import org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager; import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter; import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor; import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionManager; import static org.assertj.core.api.Assertions.assertThat; @@ -93,7 +94,7 @@ abstract class AbstractJpaAutoConfigurationTests { return (context) -> { assertThat(context).hasNotFailed(); assertThat(context).hasSingleBean(JpaProperties.class); - assertThat(context).doesNotHaveBean(PlatformTransactionManager.class); + assertThat(context).doesNotHaveBean(TransactionManager.class); assertThat(context).doesNotHaveBean(EntityManagerFactory.class); }; } @@ -117,7 +118,7 @@ abstract class AbstractJpaAutoConfigurationTests { } @Test - void jtaTransactionManagerTakesPrecedence() { + void jpaTransactionManagerTakesPrecedenceOverSimpleDataSourceOne() { this.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceTransactionManagerAutoConfiguration.class)) .run((context) -> { assertThat(context).hasSingleBean(DataSource.class); @@ -211,7 +212,8 @@ abstract class AbstractJpaAutoConfigurationTests { @Test void usesManuallyDefinedTransactionManagerBeanIfAvailable() { this.contextRunner.withUserConfiguration(TestConfigurationWithTransactionManager.class).run((context) -> { - PlatformTransactionManager txManager = context.getBean(PlatformTransactionManager.class); + assertThat(context).hasSingleBean(TransactionManager.class); + TransactionManager txManager = context.getBean(TransactionManager.class); assertThat(txManager).isInstanceOf(CustomJpaTransactionManager.class); }); } @@ -360,7 +362,7 @@ abstract class AbstractJpaAutoConfigurationTests { static class TestConfigurationWithTransactionManager { @Bean - PlatformTransactionManager transactionManager() { + TransactionManager testTransactionManager() { return new CustomJpaTransactionManager(); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/transaction/jta/JtaAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/transaction/jta/JtaAutoConfigurationTests.java index 502d620d9d..fd14185299 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/transaction/jta/JtaAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/transaction/jta/JtaAutoConfigurationTests.java @@ -51,7 +51,6 @@ import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.jta.JtaTransactionManager; import static org.assertj.core.api.Assertions.assertThat; @@ -81,7 +80,7 @@ class JtaAutoConfigurationTests { } @Test - void customPlatformTransactionManager() { + void customTransactionManager() { this.context = new AnnotationConfigApplicationContext(CustomTransactionManagerConfig.class, JtaAutoConfiguration.class); assertThatExceptionOfType(NoSuchBeanDefinitionException.class) @@ -240,8 +239,8 @@ class JtaAutoConfigurationTests { static class CustomTransactionManagerConfig { @Bean - PlatformTransactionManager transactionManager() { - return mock(PlatformTransactionManager.class); + org.springframework.transaction.TransactionManager testTransactionManager() { + return mock(org.springframework.transaction.TransactionManager.class); } }