Do not configure a ReactiveNeo4jTransactionManager

The current arrangement with Neo4j does not allow us to know for sure
that the user intends to use `@Transactional` for reactive or imperative
operations.

The main reason for that is that the only trigger for the reactive
auto-configuration is the presence of reactor on the classpath given
that the Neo4j driver ships with both styles in the same jar. And
reactor can be on the classpath for a number of reasons that are
unrelated to imperative access (typically `WebClient`).

This commits removes the auto-configuration of the
ReactiveNeo4jAutoConfiguration and makes sure that if the user defines
one, the regular `PlatformTransactionManager` backs off. This is
a temporarily situation until we can provide a better signal that the
user intends to primarily use imperative repositories.

Closes gh-22940
pull/22948/head
Stephane Nicoll 4 years ago
parent 4398c71d12
commit d4ba55f8d6

@ -47,6 +47,7 @@ import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;
import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension; import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionManager;
/** /**
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data Neo4j. * {@link EnableAutoConfiguration Auto-configuration} for Spring Data Neo4j.
@ -106,7 +107,7 @@ public class Neo4jDataAutoConfiguration {
} }
@Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_TRANSACTION_MANAGER_BEAN_NAME) @Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_TRANSACTION_MANAGER_BEAN_NAME)
@ConditionalOnMissingBean(PlatformTransactionManager.class) @ConditionalOnMissingBean(TransactionManager.class)
public Neo4jTransactionManager transactionManager(Driver driver, DatabaseSelectionProvider databaseNameProvider, public Neo4jTransactionManager transactionManager(Driver driver, DatabaseSelectionProvider databaseNameProvider,
ObjectProvider<TransactionManagerCustomizers> optionalCustomizers) { ObjectProvider<TransactionManagerCustomizers> optionalCustomizers) {
Neo4jTransactionManager transactionManager = new Neo4jTransactionManager(driver, databaseNameProvider); Neo4jTransactionManager transactionManager = new Neo4jTransactionManager(driver, databaseNameProvider);

@ -33,7 +33,6 @@ import org.springframework.data.neo4j.core.ReactiveNeo4jClient;
import org.springframework.data.neo4j.core.ReactiveNeo4jOperations; import org.springframework.data.neo4j.core.ReactiveNeo4jOperations;
import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate; import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate;
import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext; import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext;
import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager;
import org.springframework.data.neo4j.repository.config.ReactiveNeo4jRepositoryConfigurationExtension; import org.springframework.data.neo4j.repository.config.ReactiveNeo4jRepositoryConfigurationExtension;
import org.springframework.transaction.ReactiveTransactionManager; import org.springframework.transaction.ReactiveTransactionManager;
@ -46,8 +45,7 @@ import org.springframework.transaction.ReactiveTransactionManager;
* @since 2.4.0 * @since 2.4.0
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Driver.class, ReactiveNeo4jTransactionManager.class, ReactiveTransactionManager.class, @ConditionalOnClass({ Driver.class, ReactiveNeo4jTemplate.class, ReactiveTransactionManager.class, Flux.class })
Flux.class })
@ConditionalOnBean(Driver.class) @ConditionalOnBean(Driver.class)
@AutoConfigureAfter(Neo4jDataAutoConfiguration.class) @AutoConfigureAfter(Neo4jDataAutoConfiguration.class)
@Import(Neo4jDefaultReactiveCallbacksRegistrar.class) @Import(Neo4jDefaultReactiveCallbacksRegistrar.class)
@ -74,11 +72,4 @@ public class Neo4jReactiveDataAutoConfiguration {
return new ReactiveNeo4jTemplate(neo4jClient, neo4jMappingContext, databaseNameProvider); return new ReactiveNeo4jTemplate(neo4jClient, neo4jMappingContext, databaseNameProvider);
} }
@Bean(ReactiveNeo4jRepositoryConfigurationExtension.DEFAULT_TRANSACTION_MANAGER_BEAN_NAME)
@ConditionalOnMissingBean(ReactiveTransactionManager.class)
public ReactiveTransactionManager reactiveTransactionManager(Driver driver,
ReactiveDatabaseSelectionProvider databaseNameProvider) {
return new ReactiveNeo4jTransactionManager(driver, databaseNameProvider);
}
} }

@ -31,6 +31,8 @@ import org.springframework.data.neo4j.core.Neo4jTemplate;
import org.springframework.data.neo4j.core.convert.Neo4jConversions; import org.springframework.data.neo4j.core.convert.Neo4jConversions;
import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.ReactiveTransactionManager;
import org.springframework.transaction.TransactionManager;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -119,6 +121,13 @@ class Neo4jDataAutoConfigurationTests {
}); });
} }
@Test
void shouldBackoffIfReactiveTransactionManagerIsSet() {
this.contextRunner.withBean(ReactiveTransactionManager.class, () -> mock(ReactiveTransactionManager.class))
.run((context) -> assertThat(context).doesNotHaveBean(Neo4jTransactionManager.class)
.hasSingleBean(TransactionManager.class));
}
@Test @Test
void shouldReuseExistingTransactionManager() { void shouldReuseExistingTransactionManager() {
this.contextRunner this.contextRunner

@ -30,8 +30,8 @@ import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider;
import org.springframework.data.neo4j.core.ReactiveNeo4jClient; import org.springframework.data.neo4j.core.ReactiveNeo4jClient;
import org.springframework.data.neo4j.core.ReactiveNeo4jOperations; import org.springframework.data.neo4j.core.ReactiveNeo4jOperations;
import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate; import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate;
import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager;
import org.springframework.transaction.ReactiveTransactionManager; import org.springframework.transaction.ReactiveTransactionManager;
import org.springframework.transaction.TransactionManager;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -113,23 +113,12 @@ class Neo4jReactiveDataAutoConfigurationTests {
} }
@Test @Test
void shouldProvideReactiveTransactionManager() { void shouldUseExistingReactiveTransactionManager() {
this.contextRunner.withUserConfiguration(CustomReactiveDatabaseSelectionProviderConfiguration.class)
.run((context) -> {
assertThat(context).hasSingleBean(ReactiveNeo4jTransactionManager.class);
assertThat(context.getBean(ReactiveNeo4jTransactionManager.class))
.extracting("databaseSelectionProvider")
.isSameAs(context.getBean(ReactiveDatabaseSelectionProvider.class));
});
}
@Test
void shouldReuseExistingReactiveTransactionManager() {
this.contextRunner this.contextRunner
.withBean("myCustomReactiveTransactionManager", ReactiveTransactionManager.class, .withBean("myCustomReactiveTransactionManager", ReactiveTransactionManager.class,
() -> mock(ReactiveTransactionManager.class)) () -> mock(ReactiveTransactionManager.class))
.run((context) -> assertThat(context).hasSingleBean(ReactiveTransactionManager.class) .run((context) -> assertThat(context).hasSingleBean(ReactiveTransactionManager.class)
.hasBean("myCustomReactiveTransactionManager")); .hasSingleBean(TransactionManager.class));
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)

@ -28,7 +28,7 @@ import org.springframework.boot.autoconfigure.data.neo4j.country.CountryReposito
import org.springframework.boot.autoconfigure.data.neo4j.country.ReactiveCountryRepository; import org.springframework.boot.autoconfigure.data.neo4j.country.ReactiveCountryRepository;
import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate;
import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;
import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories; import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories;
@ -57,7 +57,7 @@ public class Neo4jReactiveRepositoriesAutoConfigurationTests {
@Test @Test
void configurationWithNoRepositories() { void configurationWithNoRepositories() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> assertThat(context) this.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> assertThat(context)
.hasSingleBean(ReactiveNeo4jTransactionManager.class).doesNotHaveBean(ReactiveNeo4jRepository.class)); .hasSingleBean(ReactiveNeo4jTemplate.class).doesNotHaveBean(ReactiveNeo4jRepository.class));
} }
@Test @Test
@ -70,7 +70,7 @@ public class Neo4jReactiveRepositoriesAutoConfigurationTests {
@Test @Test
void autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRepositories() { void autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRepositories() {
this.contextRunner.withUserConfiguration(SortOfInvalidCustomConfiguration.class) this.contextRunner.withUserConfiguration(SortOfInvalidCustomConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(ReactiveNeo4jTransactionManager.class) .run((context) -> assertThat(context).hasSingleBean(ReactiveNeo4jTemplate.class)
.doesNotHaveBean(ReactiveNeo4jRepository.class)); .doesNotHaveBean(ReactiveNeo4jRepository.class));
} }

Loading…
Cancel
Save