From 4b1b2d66032e578947d6ae08a048de342f81aa18 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 9 Jul 2021 10:29:50 +0100 Subject: [PATCH] Consider Flyway and Liquibase as possible Batch DB initializers This is a follow-on from 3fec4110 which only considered BatchDataSourceInitializer as a possible initializer of Batch's database schema. Flyway and Liquibase are now also considered. Closes gh-27193 --- .../batch/BatchAutoConfiguration.java | 53 +++++++++++++------ .../session/JdbcSessionConfiguration.java | 14 +++++ .../batch/BatchAutoConfigurationTests.java | 32 +++++++++++ 3 files changed, 84 insertions(+), 15 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfiguration.java index dee16f5b36..0cd8f94712 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfiguration.java @@ -18,6 +18,9 @@ package org.springframework.boot.autoconfigure.batch; import javax.sql.DataSource; +import liquibase.integration.spring.SpringLiquibase; +import org.flywaydb.core.Flyway; + import org.springframework.batch.core.configuration.ListableJobLocator; import org.springframework.batch.core.converter.JobParametersConverter; import org.springframework.batch.core.explore.JobExplorer; @@ -30,11 +33,11 @@ import org.springframework.boot.ExitCodeGenerator; import org.springframework.boot.autoconfigure.AbstractDependsOnBeanFactoryPostProcessor; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration.DataSourceInitializerConfiguration.DataSourceInitializationJobRepositoryDependencyConfiguration; 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.flyway.FlywayMigrationInitializer; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -102,11 +105,9 @@ public class BatchAutoConfiguration { return factory; } - // Fully-qualified to work around javac bug - @org.springframework.context.annotation.Configuration(proxyBeanMethods = false) - @org.springframework.boot.autoconfigure.condition.ConditionalOnBean(DataSource.class) - @org.springframework.boot.autoconfigure.condition.ConditionalOnClass(DatabasePopulator.class) - @org.springframework.context.annotation.Import(DataSourceInitializationJobRepositoryDependencyConfiguration.class) + @Configuration(proxyBeanMethods = false) + @ConditionalOnBean(DataSource.class) + @ConditionalOnClass(DatabasePopulator.class) static class DataSourceInitializerConfiguration { @Bean @@ -118,17 +119,39 @@ public class BatchAutoConfiguration { properties); } - /** - * Post processor to ensure that {@link JobRepository} beans depend on any - * {@link BatchDataSourceInitializer} beans. - */ - static class DataSourceInitializationJobRepositoryDependencyConfiguration - extends AbstractDependsOnBeanFactoryPostProcessor { + } - DataSourceInitializationJobRepositoryDependencyConfiguration() { - super(JobRepository.class, BatchDataSourceInitializer.class); - } + @Configuration(proxyBeanMethods = false) + static class JobRepositoryDependencyConfiguration { + @Bean + JobRepositoryDependsOnBeanFactoryPostProcessor batchDataSourceInitializerJobRepositoryDependsOnBeanFactoryPostProcessor() { + return new JobRepositoryDependsOnBeanFactoryPostProcessor(BatchDataSourceInitializer.class); + } + + @Bean + @ConditionalOnClass(name = "org.flywaydb.core.Flyway") + JobRepositoryDependsOnBeanFactoryPostProcessor flywayJobRepositoryDependsOnBeanFactoryPostProcessor() { + return new JobRepositoryDependsOnBeanFactoryPostProcessor(FlywayMigrationInitializer.class, Flyway.class); + } + + @Bean + @ConditionalOnClass(name = "liquibase.integration.spring.SpringLiquibase") + JobRepositoryDependsOnBeanFactoryPostProcessor liquibaseJobRepositoryDependsOnBeanFactoryPostProcessor() { + return new JobRepositoryDependsOnBeanFactoryPostProcessor(FlywayMigrationInitializer.class, + SpringLiquibase.class); + } + + } + + /** + * {@link AbstractDependsOnBeanFactoryPostProcessor} for Spring Batch + * {@link JobRepository}. + */ + static class JobRepositoryDependsOnBeanFactoryPostProcessor extends AbstractDependsOnBeanFactoryPostProcessor { + + JobRepositoryDependsOnBeanFactoryPostProcessor(Class... dependencyTypes) { + super(JobRepository.class, dependencyTypes); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionConfiguration.java index aa9e79002b..e8e749a8a9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionConfiguration.java @@ -22,6 +22,7 @@ import javax.sql.DataSource; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AbstractDependsOnBeanFactoryPostProcessor; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -80,4 +81,17 @@ class JdbcSessionConfiguration { } + /** + * Post processor to ensure that {@link JdbcIndexedSessionRepository} beans depend on + * any {@link JdbcSessionDataSourceInitializer} beans. + */ + static class DataSourceInitializationJdbcIndexedSessionRepositoryDependencyConfiguration + extends AbstractDependsOnBeanFactoryPostProcessor { + + DataSourceInitializationJdbcIndexedSessionRepositoryDependencyConfiguration() { + super(JdbcIndexedSessionRepository.class, JdbcSessionDataSourceInitializer.class); + } + + } + } 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 dcb1c7914f..a661550407 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 @@ -44,7 +44,9 @@ import org.springframework.boot.CommandLineRunner; import org.springframework.boot.DefaultApplicationArguments; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; +import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; +import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.test.City; import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; @@ -283,6 +285,36 @@ class BatchAutoConfigurationTests { }); } + @Test + void jobRepositoryBeansDependOnFlyway() { + this.contextRunner.withUserConfiguration(TestConfiguration.class, EmbeddedDataSourceConfiguration.class) + .withUserConfiguration(FlywayAutoConfiguration.class) + .withPropertyValues("spring.batch.initialize-schema=never").run((context) -> { + ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); + String[] jobRepositoryNames = beanFactory.getBeanNamesForType(JobRepository.class); + assertThat(jobRepositoryNames).isNotEmpty(); + for (String jobRepositoryName : jobRepositoryNames) { + assertThat(beanFactory.getBeanDefinition(jobRepositoryName).getDependsOn()).contains("flyway", + "flywayInitializer"); + } + }); + } + + @Test + void jobRepositoryBeansDependOnLiquibase() { + this.contextRunner.withUserConfiguration(TestConfiguration.class, EmbeddedDataSourceConfiguration.class) + .withUserConfiguration(LiquibaseAutoConfiguration.class) + .withPropertyValues("spring.batch.initialize-schema=never").run((context) -> { + ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); + String[] jobRepositoryNames = beanFactory.getBeanNamesForType(JobRepository.class); + assertThat(jobRepositoryNames).isNotEmpty(); + for (String jobRepositoryName : jobRepositoryNames) { + assertThat(beanFactory.getBeanDefinition(jobRepositoryName).getDependsOn()) + .contains("liquibase"); + } + }); + } + @Configuration(proxyBeanMethods = false) protected static class BatchDataSourceConfiguration {