From ebccedcfdde14a64280aa0e3b5a8438bc84f6fd2 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 9 Apr 2015 15:31:19 -0700 Subject: [PATCH] Add FlywayMigrationStrategy support Update FlywayAutoConfiguration to support pluggable migration strategies. Rather than always calling flyway.migrate(), users can now provide a FlywayMigrationStrategy @Bean to call whatever methods they wish. Fixes gh-1814 --- ...yManagerFactoryDependsOnPostProcessor.java | 13 +++--- .../flyway/FlywayAutoConfiguration.java | 43 +++++++++++++++++-- .../flyway/FlywayMigrationStrategy.java | 34 +++++++++++++++ .../flyway/FlywayAutoConfigurationTests.java | 31 ++++++++++++- 4 files changed, 112 insertions(+), 9 deletions(-) create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationStrategy.java diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jpa/EntityManagerFactoryDependsOnPostProcessor.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jpa/EntityManagerFactoryDependsOnPostProcessor.java index 53a06475fe..f0311aceda 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jpa/EntityManagerFactoryDependsOnPostProcessor.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jpa/EntityManagerFactoryDependsOnPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 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. @@ -45,9 +45,9 @@ import org.springframework.util.StringUtils; public class EntityManagerFactoryDependsOnPostProcessor implements BeanFactoryPostProcessor { - private final String dependsOn; + private final String[] dependsOn; - public EntityManagerFactoryDependsOnPostProcessor(String dependsOn) { + public EntityManagerFactoryDependsOnPostProcessor(String... dependsOn) { this.dependsOn = dependsOn; } @@ -55,8 +55,11 @@ public class EntityManagerFactoryDependsOnPostProcessor implements public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { for (String beanName : getEntityManagerFactoryBeanNames(beanFactory)) { BeanDefinition definition = getBeanDefinition(beanName, beanFactory); - definition.setDependsOn(StringUtils.addStringToArray( - definition.getDependsOn(), this.dependsOn)); + String[] dependencies = definition.getDependsOn(); + for (String bean : this.dependsOn) { + dependencies = StringUtils.addStringToArray(dependencies, bean); + } + definition.setDependsOn(dependencies); } } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java index 2d712213b5..ed6e4d5129 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 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. @@ -21,6 +21,7 @@ import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; import org.flywaydb.core.Flyway; +import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -95,7 +96,13 @@ public class FlywayAutoConfiguration { return false; } - @Bean(initMethod = "migrate") + @Bean + @ConditionalOnMissingBean + public FlywayMigrationStrategy flywayMigrationStrategy() { + return new FlywayMigrationStrategy(); + } + + @Bean @ConfigurationProperties(prefix = "flyway") public Flyway flyway() { Flyway flyway = new Flyway(); @@ -113,6 +120,13 @@ public class FlywayAutoConfiguration { return flyway; } + @Bean + public FlywayMigrationInitializer flywayInitializer(Flyway flyway, + FlywayMigrationStrategy migrationStrategy) { + return new FlywayMigrationInitializer(flyway, migrationStrategy); + + } + } /** @@ -126,7 +140,30 @@ public class FlywayAutoConfiguration { EntityManagerFactoryDependsOnPostProcessor { public FlywayJpaDependencyConfiguration() { - super("flyway"); + super("flywayInitializer", "flyway"); + } + + } + + /** + * {@link InitializingBean} used to trigger {@link Flyway} migration via the + * {@link FlywayMigrationStrategy}. + */ + private static class FlywayMigrationInitializer implements InitializingBean { + + private final Flyway flyway; + + private final FlywayMigrationStrategy migrationStrategy; + + public FlywayMigrationInitializer(Flyway flyway, + FlywayMigrationStrategy migrationStrategy) { + this.flyway = flyway; + this.migrationStrategy = migrationStrategy; + } + + @Override + public void afterPropertiesSet() throws Exception { + this.migrationStrategy.migrate(this.flyway); } } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationStrategy.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationStrategy.java new file mode 100644 index 0000000000..4bfbc3674d --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayMigrationStrategy.java @@ -0,0 +1,34 @@ +/* + * Copyright 2012-2015 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.flyway; + +import org.flywaydb.core.Flyway; + +/** + * Strategy used to initialize {@link Flyway} migration. Custom implementations may be + * registered as a {@code @Bean} to override the default migration behavior. + * + * @author Andreas Ahlenstorf + * @author Phillip Webb + */ +public class FlywayMigrationStrategy { + + public void migrate(Flyway flyway) { + flyway.migrate(); + } + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java index 75cdec1ddd..468a2313d1 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 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. @@ -34,9 +34,12 @@ import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; +import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; /** * Tests for {@link FlywayAutoConfiguration}. @@ -148,6 +151,16 @@ public class FlywayAutoConfigurationTests { FlywayAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class); } + @Test + public void customFlywayMigrationStrategy() throws Exception { + registerAndRefresh(EmbeddedDataSourceConfiguration.class, + FlywayAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class, + MockFlywayMigrationStrategy.class); + assertNotNull(this.context.getBean(Flyway.class)); + this.context.getBean(MockFlywayMigrationStrategy.class).assertCalled(); + } + private void registerAndRefresh(Class... annotatedClasses) { this.context.register(annotatedClasses); this.context.refresh(); @@ -165,4 +178,20 @@ public class FlywayAutoConfigurationTests { } } + + @Component + protected static class MockFlywayMigrationStrategy extends FlywayMigrationStrategy { + + private boolean called = false; + + @Override + public void migrate(Flyway flyway) { + this.called = true; + } + + public void assertCalled() { + assertThat(this.called, equalTo(true)); + } + } + }