I have a spring boot project that has multiple modules. I would like all of them to have separate flyway configurations. For example:
@Component
@AutoConfigureAfter({ DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class })
@PropertySource("classpath:flyway.properties")
public class FlywayConfig {
@PostConstruct
public void startMigrations() {
if(enabled) {
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setSchemas(schema);
flyway.setLocations(flywayLocation);
flyway.setSqlMigrationPrefix(prefix);
flyway.migrate();
}
}
}
The problem is the same as the one described here. In short, the hibernate validation starts before flyway and throws an exception because flyway has not created the tables yet.
The solution in that case does not work for me, because I dont have configuration for the beans connected with hibernate (I use the spring boot AutoConfiguration).
I checked out the FlywayAutoConfiguration and noticed that there is something like this:
@AutoConfigureAfter({ DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class })
But that does not work in my case.
I would prefer not to override the beans from the spring boot AutoConfiguration in order to add @DependsOn
(like in the solution on the question I posted above). I don't see a reason to create a bean for the flyway configurations because they need to be executed once, on the start of the application.
I also use a parent module, that merges most of the modules together but sometimes I would like to exclude/include a module before build. If I use the @DependsOn
annotation on a bean
that I will have to override in the parent module, it would mean that I will have to update the code before every build.
So, my question is: Is there another way to force the execution of flyway before the execution of the hibernate validation?
I did not manage to find a way to execute the flyway migrations without creating flyway beans, but I did manage to evade the usage of the @DependsOn
annotation.
Here is how my flyway beans look like:
Uploader module:
@Configuration
public class FlywayConfigUploader {
@Bean("flywayUploader")
public Flyway startMigrations() {
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setSchemas(schema);
flyway.setLocations(flywayLocation);
flyway.setSqlMigrationPrefix(prefix);
return flyway;
}
}
Processing module:
@Configuration
public class FlywayConfigProcessor {
@Bean("flywayProcessor")
public Flyway startMigrations() {
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setSchemas(schema);
flyway.setLocations(flywayLocation);
flyway.setSqlMigrationPrefix(prefix);
return flyway;
}
}
The project currently has 10 modules (so there are 10 of these flyway configurations). The number of modules will probably increase in the future.
I overrode the LocalContainerEntityManagerFactoryBean
like in this answer.
But instead of using the DependsOn
annotation I added all of the flyway beans as a dependency to the LocalContainerEntityManagerFactoryBean
bean.
@Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean
postgresEntityManagerFactory(EntityManagerFactoryBuilder builder, DataSource dataSource,
List<Flyway> flywayBeans) {
flywayBeans.forEach(el -> el.migrate());
//Rest of the code from the method is not relevant for the question
}
This way there is no need for code updates when the user decides to exclude or include modules, because every module has a flyway bean that will be created only if the module is included in the build.
This way we can also control the order execution of the flyway migrations. For example we might have a base module on which other modules depend, so migrations from that module have to be executed first. In that scenario, we could wrap the flyway configurations in a wrapper beans that will contain information about their order.
public class FlywayWrapper {
private Flyway flywayConfig;
private Integer order;
}
Before executing the migrations, we could sort them by their order.
flywayBeans.sort(Comparator.comparing(FlywayWrapper::getOrder));
flywayBeans.forEach(el -> el.getFlywayConfig().migrate());