diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java index 742577d68a..837372f862 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java @@ -29,6 +29,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.domain.EntityScanner; import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; +import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizationAutoConfiguration; import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.ApplicationContext; @@ -58,7 +59,8 @@ import org.springframework.transaction.TransactionManager; * @author Michael J. Simons * @since 1.4.0 */ -@AutoConfiguration(before = TransactionAutoConfiguration.class, after = Neo4jAutoConfiguration.class) +@AutoConfiguration(before = TransactionAutoConfiguration.class, + after = { Neo4jAutoConfiguration.class, TransactionManagerCustomizationAutoConfiguration.class }) @ConditionalOnClass({ Driver.class, Neo4jTransactionManager.class, PlatformTransactionManager.class }) @EnableConfigurationProperties(Neo4jDataProperties.class) @ConditionalOnBean(Driver.class) 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 e144521271..55bbd9cfeb 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 @@ -26,6 +26,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; +import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizationAutoConfiguration; import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -46,7 +47,8 @@ import org.springframework.transaction.TransactionManager; * @author Kazuki Shimizu * @since 1.0.0 */ -@AutoConfiguration(before = TransactionAutoConfiguration.class) +@AutoConfiguration(before = TransactionAutoConfiguration.class, + after = TransactionManagerCustomizationAutoConfiguration.class) @ConditionalOnClass({ JdbcTemplate.class, TransactionManager.class }) @AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE) @EnableConfigurationProperties(DataSourceProperties.class) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.java index 0dfdd3eb8b..9eb2c932e5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.java @@ -24,6 +24,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; +import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizationAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Import; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; @@ -37,7 +38,9 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; * @author Andy Wilkinson * @since 1.0.0 */ -@AutoConfiguration(after = DataSourceAutoConfiguration.class, before = TransactionAutoConfiguration.class) +@AutoConfiguration( + after = { DataSourceAutoConfiguration.class, TransactionManagerCustomizationAutoConfiguration.class }, + before = TransactionAutoConfiguration.class) @ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class, EntityManager.class, SessionImplementor.class }) @EnableConfigurationProperties(JpaProperties.class) @Import(HibernateJpaConfiguration.class) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/TransactionAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/TransactionAutoConfiguration.java index 2c605e050a..1742d8ea0b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/TransactionAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/TransactionAutoConfiguration.java @@ -16,14 +16,12 @@ package org.springframework.boot.autoconfigure.transaction; -import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; -import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.transaction.PlatformTransactionManager; @@ -44,16 +42,8 @@ import org.springframework.transaction.support.TransactionTemplate; */ @AutoConfiguration @ConditionalOnClass(PlatformTransactionManager.class) -@EnableConfigurationProperties(TransactionProperties.class) public class TransactionAutoConfiguration { - @Bean - @ConditionalOnMissingBean - public TransactionManagerCustomizers platformTransactionManagerCustomizers( - ObjectProvider> customizers) { - return new TransactionManagerCustomizers(customizers.orderedStream().toList()); - } - @Bean @ConditionalOnMissingBean @ConditionalOnSingleCandidate(ReactiveTransactionManager.class) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/TransactionManagerCustomizationAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/TransactionManagerCustomizationAutoConfiguration.java new file mode 100644 index 0000000000..692123bae4 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/TransactionManagerCustomizationAutoConfiguration.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2023 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.transaction; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionManager; + +/** + * Auto-configuration for the customization of a {@link TransactionManager}. + * + * @author Andy Wilkinson + * @since 3.2.0 + */ +@ConditionalOnClass(PlatformTransactionManager.class) +@AutoConfiguration(before = TransactionAutoConfiguration.class) +@EnableConfigurationProperties(TransactionProperties.class) +public class TransactionManagerCustomizationAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + TransactionManagerCustomizers platformTransactionManagerCustomizers( + ObjectProvider> customizers) { + return new TransactionManagerCustomizers(customizers.orderedStream().toList()); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/jta/JtaAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/jta/JtaAutoConfiguration.java index a9040ac4ba..480e32b81d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/jta/JtaAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/jta/JtaAutoConfiguration.java @@ -25,6 +25,7 @@ import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfigura import org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; +import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizationAutoConfiguration; import org.springframework.context.annotation.Import; /** @@ -36,7 +37,8 @@ import org.springframework.context.annotation.Import; * @since 1.2.0 */ @AutoConfiguration(before = { XADataSourceAutoConfiguration.class, ActiveMQAutoConfiguration.class, - ArtemisAutoConfiguration.class, HibernateJpaAutoConfiguration.class, TransactionAutoConfiguration.class }) + ArtemisAutoConfiguration.class, HibernateJpaAutoConfiguration.class, TransactionAutoConfiguration.class, + TransactionManagerCustomizationAutoConfiguration.class }) @ConditionalOnClass(jakarta.transaction.Transaction.class) @ConditionalOnProperty(prefix = "spring.jta", value = "enabled", matchIfMissing = true) @Import(JndiJtaConfiguration.class) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 7f6c606cd0..c8fbc3b8d5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -124,6 +124,7 @@ org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration +org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizationAutoConfiguration org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java index 9d508642d2..b57be44564 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java @@ -61,6 +61,7 @@ import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportL import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.test.City; import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; +import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizationAutoConfiguration; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; import org.springframework.boot.logging.LogLevel; @@ -100,9 +101,9 @@ import static org.mockito.Mockito.mock; @ExtendWith(OutputCaptureExtension.class) class BatchAutoConfigurationTests { - private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(BatchAutoConfiguration.class, TransactionAutoConfiguration.class, - DataSourceTransactionManagerAutoConfiguration.class)); + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration( + AutoConfigurations.of(BatchAutoConfiguration.class, TransactionManagerCustomizationAutoConfiguration.class, + TransactionAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class)); @Test void testDefaultContext() { 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 9004444043..a289503b02 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 @@ -24,6 +24,7 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; +import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizationAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.jdbc.support.JdbcTransactionManager; @@ -44,6 +45,7 @@ class DataSourceTransactionManagerAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(TransactionAutoConfiguration.class, + TransactionManagerCustomizationAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class)) .withPropertyValues("spring.datasource.url:jdbc:hsqldb:mem:test-" + UUID.randomUUID()); 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 38909c284b..869607e7e8 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 @@ -39,6 +39,7 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerA import org.springframework.boot.autoconfigure.orm.jpa.test.City; import org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration; import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; +import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizationAutoConfiguration; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -82,7 +83,8 @@ abstract class AbstractJpaAutoConfigurationTests { "spring.jta.log-dir=" + new File(new BuildOutput(getClass()).getRootLocation(), "transaction-logs")) .withUserConfiguration(TestConfiguration.class) .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, - TransactionAutoConfiguration.class, SqlInitializationAutoConfiguration.class, autoConfiguredClass)); + TransactionAutoConfiguration.class, TransactionManagerCustomizationAutoConfiguration.class, + SqlInitializationAutoConfiguration.class, autoConfiguredClass)); } protected ApplicationContextRunner contextRunner() { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/transaction/TransactionAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/transaction/TransactionAutoConfigurationTests.java index 502124eb17..717ba08b30 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/transaction/TransactionAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/transaction/TransactionAutoConfigurationTests.java @@ -127,18 +127,6 @@ class TransactionAutoConfigurationTests { }); } - @Test - void platformTransactionManagerCustomizers() { - this.contextRunner.withUserConfiguration(SeveralPlatformTransactionManagersConfiguration.class) - .run((context) -> { - TransactionManagerCustomizers customizers = context.getBean(TransactionManagerCustomizers.class); - assertThat(customizers).extracting("customizers") - .asList() - .singleElement() - .isInstanceOf(TransactionProperties.class); - }); - } - @Test void transactionNotManagedWithNoTransactionManager() { this.contextRunner.withUserConfiguration(BaseConfiguration.class) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/transaction/TransactionManagerCustomizationAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/transaction/TransactionManagerCustomizationAutoConfigurationTests.java new file mode 100644 index 0000000000..9fe13d8bf0 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/transaction/TransactionManagerCustomizationAutoConfigurationTests.java @@ -0,0 +1,70 @@ +/* + * Copyright 2012-2023 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.transaction; + +import java.util.Collections; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link TransactionManagerCustomizationAutoConfiguration}. + * + * @author Andy Wilkinson + */ +class TransactionManagerCustomizationAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(TransactionManagerCustomizationAutoConfiguration.class)); + + @Test + void autoConfiguresTransactionManagerCustomizers() { + this.contextRunner.run((context) -> { + TransactionManagerCustomizers customizers = context.getBean(TransactionManagerCustomizers.class); + assertThat(customizers).extracting("customizers") + .asList() + .singleElement() + .isInstanceOf(TransactionProperties.class); + }); + } + + @Test + void autoConfiguredTransactionManagerCustomizersBacksOff() { + this.contextRunner.withUserConfiguration(CustomTransactionManagerCustomizersConfiguration.class) + .run((context) -> { + TransactionManagerCustomizers customizers = context.getBean(TransactionManagerCustomizers.class); + assertThat(customizers).extracting("customizers").asList().isEmpty(); + }); + } + + @Configuration(proxyBeanMethods = false) + static class CustomTransactionManagerCustomizersConfiguration { + + @Bean + TransactionManagerCustomizers customTransactionManagerCustomizers() { + return new TransactionManagerCustomizers(Collections.emptyList()); + } + + } + +}