Reputation: 1105
I have a spring boot based application that I want to run Flyway migrations on. The app needs to run the flyway migrate only under certain circumstances. For instance if the "migrate" argument is passed to Main().
There also are 2 different Datasources that need to be migrated.
@SpringBootApplication
public class ExampleMain implements CommandLineRunner {
public static void main(String[] args) {
new SpringApplicationBuilder(ExampleMain.class)
.web(WebApplicationType.NONE)
.run(args);
}
@Override
public void run(String... args) throws Exception {
if (args[0].equals("migrate"))
migrate();
else
System.out.println("The world is round");
}
private void migrate() {
createFlywayForDb1().migrate();
createFlywayForDb2().migrate();
}
private Flyway createFlywayForDb1() {
return createFlyway("XXX", "XXX", "XXX", new String[] { "classpath:com/example/migrations/db1" } );
}
private Flyway createFlywayForDb2() {
return createFlyway("ZZZ", "ZZZ", "ZZZ", new String[] { "classpath:com/example/migrations/db2" } );
}
private Flyway createFlyway(String url, String userName, String userPassword, String[] locations) {
return Flyway.configure()
.dataSource(url, userName, userPassword)
.locations(locations)
.ignoreMissingMigrations(true)
.ignoreIgnoredMigrations(true)
.load();
}
}
The Flyway.migrate() won't work in this case because the Java migration classes need their spring boot beans injected. Is there some way to Autoload a Flyway instance?
I've read this but can't find a way to do the above. Any help would be greatly appreciated!
Upvotes: 1
Views: 2834
Reputation: 1998
I've managed run it by importing in a separate application, or alternative main class from same app by:
/**
* Utility to run flyway migration without starting service
* from: https://medium.com/@viveka_singh/spring-boot-execute-flyway-migrations-ahead-of-service-deployment-340d0618ee3b
*/
@SpringBootConfiguration
@Import({DataSourceAutoConfiguration.class, FlywayAutoConfiguration.class}) // <-- HERE IS THE TRICK!
public class FlywayMigrationRunner {
private static final Logger LOGGER = LoggerFactory.getLogger(FlywayMigrationRunner.class);
public static void main(String[] args) {
LOGGER.info("FlywayMigrationRunner begin");
SpringApplication application = new SpringApplicationBuilder(FlywayMigrationRunner.class)
.web(WebApplicationType.NONE)
.build();
application.run(args);
LOGGER.info("FlywayMigrationRunner end");
}
}
inspired from: https://medium.com/@viveka_singh/spring-boot-execute-flyway-migrations-ahead-of-service-deployment-340d0618ee3b
Upvotes: 0
Reputation: 13860
First, you need to stop Spring Boot from executing Flyway migrations on startup. If you define a bean implementing FlywayMigrationStrategy, then Spring Boot will invoke that bean instead of directly invoking Flyway to execute the migrations. The implementation will not actually execute the migrations.
@Bean
public FlywayMigrationStrategy noopFlywayMigrationStrategy() {
return flyway -> System.out.println("I'm not migrating right now.");
}
Spring Boot auto-configures a Flyway bean which you can inject into you application. Invoke the migrate method on that bean to execute the migrations.
@SpringBootApplication
public class ExampleMain implements CommandLineRunner {
@Autowired
private Flyway flyway;
@Override
public void run(String... args) throws Exception {
if (args[0].equals("migrate")) {
flyway.migrate();
}
}
public static void main(String[] args) {
new SpringApplicationBuilder(ExampleMain.class)
.web(WebApplicationType.NONE)
.run(args);
}
}
Upvotes: 2