From 2ba593328fa3bb74165a0a5c4eb14eb5ab58ad90 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 22 Sep 2021 18:30:44 +0100 Subject: [PATCH] Order detector for AbstractDataSourceInitializers Previously, the detector for AbstractDataSourceInitializers used the default detector order. This resulted in the initializers detected initializers running before Flyway. Constrastingly, the detector for DataSourceScriptDatabaseInitializers uses a custom order so its detected initializers would run after Flyway. This commit aligns the order of the detector for AbstractDataSourceInitializers with the order of the detector for DataSourceScriptDatabaseInitializers. This ensures that script-based initialization runs in the same order with respect to Flyway, irrespective of which initializer implementation is driving it. Fixes gh-28079 --- .../IntegrationAutoConfigurationTests.java | 32 +++++++++++++++---- ...nitializerDatabaseInitializerDetector.java | 8 +++++ 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java index 03d1f5cc86..9814cb0d37 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java @@ -21,10 +21,10 @@ import javax.management.MBeanServer; import io.rsocket.transport.ClientTransport; import io.rsocket.transport.netty.client.TcpClientTransport; import org.junit.jupiter.api.Test; -import reactor.core.publisher.Mono; import org.springframework.beans.DirectFieldAccessor; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; import org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration.IntegrationComponentScanConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; @@ -44,10 +44,8 @@ import org.springframework.integration.annotation.IntegrationComponentScan; import org.springframework.integration.annotation.MessagingGateway; import org.springframework.integration.config.IntegrationManagementConfigurer; import org.springframework.integration.context.IntegrationContextUtils; -import org.springframework.integration.core.MessageSource; import org.springframework.integration.endpoint.MessageProcessorMessageSource; import org.springframework.integration.gateway.RequestReplyExchanger; -import org.springframework.integration.handler.MessageProcessor; import org.springframework.integration.rsocket.ClientRSocketConnector; import org.springframework.integration.rsocket.IntegrationRSocketEndpoint; import org.springframework.integration.rsocket.ServerRSocketConnector; @@ -166,6 +164,27 @@ class IntegrationAutoConfigurationTests { }); } + @Test + void whenIntegrationJdbcDataSourceInitializerIsEnabledThenFlywayCanBeUsed() { + this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) + .withConfiguration(AutoConfigurations.of(DataSourceTransactionManagerAutoConfiguration.class, + JdbcTemplateAutoConfiguration.class, IntegrationAutoConfiguration.class, + FlywayAutoConfiguration.class)) + .withPropertyValues("spring.datasource.generate-unique-name=true", + "spring.integration.jdbc.initialize-schema=always") + .run((context) -> { + IntegrationProperties properties = context.getBean(IntegrationProperties.class); + assertThat(properties.getJdbc().getInitializeSchema()) + .isEqualTo(DataSourceInitializationMode.ALWAYS); + JdbcOperations jdbc = context.getBean(JdbcOperations.class); + assertThat(jdbc.queryForList("select * from INT_MESSAGE")).isEmpty(); + assertThat(jdbc.queryForList("select * from INT_GROUP_TO_MESSAGE")).isEmpty(); + assertThat(jdbc.queryForList("select * from INT_MESSAGE_GROUP")).isEmpty(); + assertThat(jdbc.queryForList("select * from INT_LOCK")).isEmpty(); + assertThat(jdbc.queryForList("select * from INT_CHANNEL_MESSAGE")).isEmpty(); + }); + } + @Test void integrationJdbcDataSourceInitializerDisabled() { this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) @@ -362,8 +381,9 @@ class IntegrationAutoConfigurationTests { static class MessageSourceConfiguration { @Bean - MessageSource myMessageSource() { - return new MessageProcessorMessageSource(mock(MessageProcessor.class)); + org.springframework.integration.core.MessageSource myMessageSource() { + return new MessageProcessorMessageSource( + mock(org.springframework.integration.handler.MessageProcessor.class)); } } @@ -376,7 +396,7 @@ class IntegrationAutoConfigurationTests { return new IntegrationRSocketEndpoint() { @Override - public Mono handleMessage(Message message) { + public reactor.core.publisher.Mono handleMessage(Message message) { return null; } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/AbstractDataSourceInitializerDatabaseInitializerDetector.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/AbstractDataSourceInitializerDatabaseInitializerDetector.java index e9ea33c233..bbb1b8c295 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/AbstractDataSourceInitializerDatabaseInitializerDetector.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/AbstractDataSourceInitializerDatabaseInitializerDetector.java @@ -21,6 +21,7 @@ import java.util.Set; import org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDatabaseInitializerDetector; import org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector; +import org.springframework.core.Ordered; /** * A {@link DatabaseInitializerDetector} for {@link AbstractDataSourceInitializer}. @@ -29,9 +30,16 @@ import org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector; */ class AbstractDataSourceInitializerDatabaseInitializerDetector extends AbstractBeansOfTypeDatabaseInitializerDetector { + private static final int PRECEDENCE = Ordered.LOWEST_PRECEDENCE - 100; + @Override protected Set> getDatabaseInitializerBeanTypes() { return Collections.singleton(AbstractDataSourceInitializer.class); } + @Override + public int getOrder() { + return PRECEDENCE; + } + }