diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java index b2a684af5c5..1deb92e3fe8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java @@ -31,6 +31,7 @@ import org.flywaydb.core.Flyway; import org.flywaydb.core.api.MigrationVersion; import org.flywaydb.core.api.callback.Callback; import org.flywaydb.core.api.configuration.FluentConfiguration; +import org.flywaydb.core.api.migration.JavaMigration; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -112,7 +113,7 @@ public class FlywayAutoConfiguration { ResourceLoader resourceLoader, ObjectProvider dataSource, @FlywayDataSource ObjectProvider flywayDataSource, ObjectProvider fluentConfigurationCustomizers, - ObjectProvider callbacks) { + ObjectProvider javaMigrations, ObjectProvider callbacks) { FluentConfiguration configuration = new FluentConfiguration(resourceLoader.getClassLoader()); DataSource dataSourceToMigrate = configureDataSource(configuration, properties, dataSourceProperties, flywayDataSource.getIfAvailable(), dataSource.getIfAvailable()); @@ -122,6 +123,8 @@ public class FlywayAutoConfiguration { configureCallbacks(configuration, orderedCallbacks); fluentConfigurationCustomizers.orderedStream().forEach((customizer) -> customizer.customize(configuration)); configureFlywayCallbacks(configuration, orderedCallbacks); + List migrations = javaMigrations.stream().collect(Collectors.toList()); + configureJavaMigrations(configuration, migrations); return configuration.load(); } @@ -215,6 +218,12 @@ public class FlywayAutoConfiguration { } } + private void configureJavaMigrations(FluentConfiguration flyway, List migrations) { + if (!migrations.isEmpty()) { + flyway.javaMigrations(migrations.toArray(new JavaMigration[0])); + } + } + private String getProperty(Supplier property, Supplier defaultValue) { String value = property.get(); return (value != null) ? value : defaultValue.get(); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java index 1a4e0cd4c42..9814ae364b5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java @@ -29,6 +29,7 @@ import org.flywaydb.core.api.MigrationVersion; import org.flywaydb.core.api.callback.Callback; import org.flywaydb.core.api.callback.Context; import org.flywaydb.core.api.callback.Event; +import org.flywaydb.core.api.migration.JavaMigration; import org.flywaydb.core.internal.license.FlywayProUpgradeRequiredException; import org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform; import org.junit.jupiter.api.Test; @@ -264,6 +265,16 @@ class FlywayAutoConfigurationTests { }); } + @Test + void flywayJavaMigrations() { + this.contextRunner + .withUserConfiguration(EmbeddedDataSourceConfiguration.class, FlywayJavaMigrationsConfiguration.class) + .run((context) -> { + Flyway flyway = context.getBean(Flyway.class); + assertThat(flyway.getConfiguration().getJavaMigrations().length).isEqualTo(2); + }); + } + @Test void customFlywayMigrationInitializer() { this.contextRunner @@ -471,6 +482,21 @@ class FlywayAutoConfigurationTests { } + @Configuration(proxyBeanMethods = false) + static class FlywayJavaMigrationsConfiguration { + + @Bean + TestMigration migration1() { + return new TestMigration("2", "M1"); + } + + @Bean + TestMigration migration2() { + return new TestMigration("3", "M2"); + } + + } + @Configuration(proxyBeanMethods = false) static class ResourceLoaderConfiguration { @@ -583,4 +609,47 @@ class FlywayAutoConfigurationTests { } + private static final class TestMigration implements JavaMigration { + + private final MigrationVersion version; + + private final String description; + + private TestMigration(String version, String description) { + this.version = MigrationVersion.fromVersion(version); + this.description = description; + } + + @Override + public MigrationVersion getVersion() { + return this.version; + } + + @Override + public String getDescription() { + return this.description; + } + + @Override + public Integer getChecksum() { + return 1; + } + + @Override + public boolean isUndo() { + return false; + } + + @Override + public boolean canExecuteInTransaction() { + return true; + } + + @Override + public void migrate(org.flywaydb.core.api.migration.Context context) { + + } + + } + } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc index c9c31aab88f..cf884b3b1db 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -1907,7 +1907,7 @@ Spring Boot supports two higher-level migration tools: https://flywaydb.org/[Fly ==== Execute Flyway Database Migrations on Startup To automatically run Flyway database migrations on startup, add the `org.flywaydb:flyway-core` to your classpath. -The migrations are scripts in the form `V__.sql` (with `` an underscore-separated version, such as '`1`' or '`2_1`'). +Typically, migrations are scripts in the form `V__.sql` (with `` an underscore-separated version, such as '`1`' or '`2_1`'). By default, they are in a folder called `classpath:db/migration`, but you can modify that location by setting `spring.flyway.locations`. This is a comma-separated list of one or more `classpath:` or `filesystem:` locations. For example, the following configuration would search for scripts in both the default classpath location and the `/opt/migration` directory: @@ -1928,6 +1928,8 @@ Assume the following: Rather than using `db/migration`, the preceding configuration sets the folder to use according to the type of the database (such as `db/migration/mysql` for MySQL). The list of supported databases is available in {sc-spring-boot}/jdbc/DatabaseDriver.{sc-ext}[`DatabaseDriver`]. +Migrations can also be written in Java. Flyway will be auto-configured with any beans that implement `JavaMigration`. + {sc-spring-boot-autoconfigure}/flyway/FlywayProperties.{sc-ext}[`FlywayProperties`] provides most of Flyway's settings and a small set of additional properties that can be used to disable the migrations or switch off the location checking. If you need more control over the configuration, consider registering a `FlywayConfigurationCustomizer` bean.