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
This commit is contained in:
		
							parent
							
								
									f191b7513d
								
							
						
					
					
						commit
						085091dbe3
					
				| 
						 | 
				
			
			@ -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> transactionManagerCustomizers) {
 | 
			
		||||
			DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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> transactionManagerCustomizers) {
 | 
			
		||||
		JpaTransactionManager transactionManager = new JpaTransactionManager();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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"));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue