Почему вы реализуете метод @PostContruct
? Как я вижу, FlywayMigrationStrategy
- это функциональный интерфейс, и я думаю, что ваш код должен выглядеть следующим образом:
@Bean
public FlywayMigrationStrategy cleanMigrateStrategy() {
FlywayMigrationStrategy strategy = new FlywayMigrationStrategy() {
@Override
public void migrate(Flyway flyway) {
flyway.clean();
flyway.migrate();
}
};
return strategy;
}
Хорошо, у меня есть некоторые исследования, и теперь я могу объяснить ответ на ваш вопрос.
Прежде всего, давайте проверим FlywayAutoConfiguration
Когда вы используете настройку миграции пролета через файл свойств, конфигурация работает, создает и настраивает экземпляры Flyway и переносит базу. Все они настроены в FlywayConfiguration
. Давайте посмотрим на аннотацию условия для конфигурации
@ConditionalOnMissingBean(Flyway.class)
Это означает, что конфигурация не создается, если бин для класса Flyway.class
уже существует в контексте Spring. Хорошо, затем конфигурация создает только для bean-компонентов
@Bean
public Flyway flyway(FlywayProperties properties, DataSourceProperties dataSourceProperties,
ResourceLoader resourceLoader, ObjectProvider<DataSource> dataSource,
@FlywayDataSource ObjectProvider<DataSource> flywayDataSource,
ObjectProvider<FlywayConfigurationCustomizer> fluentConfigurationCustomizers,
ObjectProvider<JavaMigration> javaMigrations, ObjectProvider<Callback> callbacks)
.....
@Bean
@ConditionalOnMissingBean
public FlywayMigrationInitializer flywayInitializer(Flyway flyway,
ObjectProvider<FlywayMigrationStrategy> migrationStrategy) {
return new FlywayMigrationInitializer(flyway, migrationStrategy.getIfAvailable());
}
Не так важно, как config конфигурирует bean-компонент flyway
, но важно, чтобы он создавал FlywayMigrationInitializer
, который инициирует миграцию. Как видите, FlywayMigrationStrategy
имеет значение FlywayMigrationInitializer
в качестве аргумента конструктора. И именно он использует MigrationStrategy, если он был установлен, в противном случае просто выполните flyway.migrate()
. (см. исходный код)
Хорошо, теперь мы знаем, как это работает в целом, давайте посмотрим в вашем коде.
Вы создаете экземпляры flyway в своей основной конфигурации:
@Bean(initMethod = "migrate")
@FlywayDataSource
public Flyway firstFlyway(DataSource dataSource) {
return new Flyway(
new FluentConfiguration()
.locations("db/first-migration")
.schemas("first")
.outOfOrder(true)
.dataSource(dataSource)
);
}
@Bean(initMethod = "migrate")
@FlywayDataSource
public Flyway secondFlyway(@Qualifier("secondDataSource") DataSource dataSource) {
return new Flyway(
new FluentConfiguration()
.dataSource(dataSource)
.schemas("second")
.outOfOrder(true)
.locations("db/second-migration")
);
}
Поскольку вы уже создаете экземпляры Flyway, FlywayConfiguration
не создается (из-за условия), и бины инициализатора для ваших бинов Flyway
также не создаются. В результате миграции не выполняются, и вам нужно добавить (initMethod = "migrate")
к объявлению компонента для начала миграции. Кроме того, я думаю, что @FlywayDataSource
не требуется и ничего не делает.
Давайте теперь go для вашей тестовой конфигурации.
Когда вы создаете FlywayMigrationStrategy
, он работает правильно, но никто не использует стратегию (в вашем основном конфигурационном файле вы называете Flyway.migrate
, так как initMethod и MigrationInitializer не создаются). В результате стратегия не выполняется.
В вашем рабочем примере вы добавили вызов clean и мигрировали в методе TestConfiguration
postconstruct. И это работает, потому что метод postconstruct выполняется после создания конфигурации. НО если вы отладите свой код, вы увидите, что метод migrate
выполняется дважды для каждого экземпляра Flyway: в виде компонента initMethod
и из метода постконтракта Testconfiguration. Я не уверен, что это то, что вам нужно.
Хорошо, для исправления я предлагаю удалить (initMethod = "migrate")
и @FlywayDataSource
, создать FlywayMigrationInitializer
bean для каждого Flyway
bean в вашей основной конфигурации и внедрите FlywayMigrationStrategy
в свою тестовую конфигурацию.
@Bean
public FlywayMigrationInitializer flywayInitializer(@Qualifier(...) Flyway flyway,
ObjectProvider<FlywayMigrationStrategy> migrationStrategy) {
return new FlywayMigrationInitializer(flyway, migrationStrategy.getIfAvailable());
}