Break cycle between TransactionManagerCustomizers and TransactionManager

Closes gh-36801
pull/37630/head
Andy Wilkinson 1 year ago
parent 72a4e1ebae
commit 96986a6b51

@ -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)

@ -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)

@ -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)

@ -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<PlatformTransactionManagerCustomizer<?>> customizers) {
return new TransactionManagerCustomizers(customizers.orderedStream().toList());
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(ReactiveTransactionManager.class)

@ -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<PlatformTransactionManagerCustomizer<?>> customizers) {
return new TransactionManagerCustomizers(customizers.orderedStream().toList());
}
}

@ -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)

@ -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

@ -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() {

@ -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());

@ -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() {

@ -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)

@ -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());
}
}
}
Loading…
Cancel
Save