Mike Cooper
Mike Cooper

Reputation: 1105

Run Flyway migrate with spring boot explicitly

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

Answers (2)

ALZ
ALZ

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

Chin Huang
Chin Huang

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

Related Questions