SpringBoot實現Flyway的Callback回調鈎子


背景

產品迭代使用CI/CD升級過程中,需要對不同發布環境的不同產品版本進行數據庫迭代升級,我們在中間某次產品迭代時加入了Flyway中間件以實現數據庫結構的自動化升級。

需求

由於是迭代過程中加入的Flyway,而不是一開始就使用,所以Flyway的版本表和版本記錄數據在已經發布過的環境中是不存在的,而且每個環境的產品版本也不同,數據庫結構迭代升級首先需要確定當前產品的版本,再執行相應的升級腳本。所以我們需要在發布環境升級時,在Flyway執行之前先根據數據庫現狀寫入版本表和版本記錄數據,才能讓Flyway正常執行迭代升級腳本。

Flyway Hooks/Callback

查閱官方文檔知道Flyway有個Hooks,官網文檔,文檔詳細描述如下:

 

Building upon that are the Java-based Callbacks when you need more power or flexibility in a Callback than SQL can offer you.

 

They can be created by implementing the Callback interface:

public class MyNotifierCallback implements Callback {
    
    // Ensures that this callback handles both events
    @Override
    public boolean supports(Event event, Context context) {
        return event.equals(Event.AFTER_MIGRATE) || event.equals(Event.AFTER_MIGRATE_ERROR);
    }
    
    // Not relevant if we don't interact with the database
    @Override
    public boolean canHandleInTransaction(Event event, Context context) {
        return true;
    }
    
    // Send a notification when either event happens.
    @Override
    public void handle(Event event, Context context) {
        String notification = event.equals(Event.AFTER_MIGRATE) ? "Success" : "Failed";
        // ... Notification logic ...
        notificationService.send(notification);
    }

    String getCallbackName() {
        return "MyNotifier";
    }
}

In order to be picked up by Flyway, Java-based Callbacks must implement the Callback interface. Flyway will automatically scan for and load all callbacks found in the db/callback package. Additional callback classes or scan locations can be specified by the flyway.callbacks configuration property.

 

SpringBoot實現

根據官方文檔描述,需要實現Callback並配置flyway.callbacks參數,但是在springboot配置文件中並沒有找到關於spring.flyway.callbacks或者flyway.callbacks的配置項

查看了下源碼找到了原因,callbacks屬性被定義為了final,所以配置文件中不能設置callbacks配置項,關鍵代碼截圖如下:

public class Flyway implements FlywayConfiguration {

    private final List<FlywayCallback> callbacks;

    public void setCallbacks(FlywayCallback... callbacks) {
        this.callbacks.clear();
        this.callbacks.addAll(Arrays.asList(callbacks));
    }

}

有個callbacks的set方法,可以嘗試用spring注入的方式配置,實現代碼如下:

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.flywaydb.core.api.MigrationInfo;
import org.flywaydb.core.api.callback.FlywayCallback;
import org.springframework.context.annotation.Configuration;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Flyway迭代升級SQL腳本鈎子
 * 主要作用:
 * 1、初始化VERSION表
 * 2、寫入當前迭代版本號,根據數據庫中是否存在數據表判斷
 */
@Slf4j
@Configuration
public class InitFlywayCallback implements FlywayCallback {
    @Override
    public void beforeClean(Connection connection) {

    }

    @Override
    public void afterClean(Connection connection) {

    }

    @Override
    public void beforeMigrate(Connection connection) {

    }

    @Override
    public void afterMigrate(Connection connection) {

    }

    @Override
    public void beforeUndo(Connection connection) {

    }

    @Override
    public void beforeEachUndo(Connection connection, MigrationInfo migrationInfo) {

    }

    @Override
    public void afterEachUndo(Connection connection, MigrationInfo migrationInfo) {

    }

    @Override
    public void afterUndo(Connection connection) {

    }

    @Override
    public void beforeEachMigrate(Connection connection, MigrationInfo migrationInfo) {

    }

    @Override
    public void afterEachMigrate(Connection connection, MigrationInfo migrationInfo) {

    }

    @SneakyThrows
    @Override
    public void beforeValidate(Connection connection) {
        log.info("Flyway執行攔截");
    }

    @Override
    public void afterValidate(Connection connection) {

    }

    @Override
    public void beforeBaseline(Connection connection) {

    }

    @Override
    public void afterBaseline(Connection connection) {

    }

    @Override
    public void beforeRepair(Connection connection) {

    }

    @Override
    public void afterRepair(Connection connection) {

    }

    @Override
    public void beforeInfo(Connection connection) {

    }

    @Override
    public void afterInfo(Connection connection) {

    }
}

項目啟動打印結果如下:

2020-12-23 09:42:53.025 dassets 13092 [--] [ INFO] [org.flywaydb.core.internal.util.VersionPrinter.info:44] [           main] [Flyway Community Edition 5.0.7 by Boxfuse] 
2020-12-23 09:43:03.461 dassets 13092 [--] [ INFO] [org.flywaydb.core.internal.database.DatabaseFactory.info:44] [           main] [Database: jdbc:mysql://10.101.6.105:3306/user (MySQL 5.7)] 
2020-12-23 09:43:03.675 dassets 13092 [--] [ INFO] [com.cestc.dassets.interceptor.InitFlywayCallback.beforeValidate:76] [           main] [Flyway執行攔截] 

至此,callback執行成功!

 

最后附一個Flyway的Callback事件描述,官網文檔

Name Execution
beforeMigrate Before Migrate runs
beforeRepeatables Before all repeatable migrations during Migrate
beforeEachMigrate Before every single migration during Migrate
beforeEachMigrateStatement Flyway Teams  Before every single statement of a migration during Migrate
afterEachMigrateStatement Flyway Teams  After every single successful statement of a migration during Migrate
afterEachMigrateStatementError Flyway Teams  After every single failed statement of a migration during Migrate
afterEachMigrate After every single successful migration during Migrate
afterEachMigrateError After every single failed migration during Migrate
afterMigrate After successful Migrate runs
afterVersioned After all versioned migrations during Migrate
afterMigrateError After failed Migrate runs
beforeUndo Flyway Teams  Before Undo runs
beforeEachUndo Flyway Teams  Before every single migration during Undo
beforeEachUndoStatement Flyway Teams  Before every single statement of a migration during Undo
afterEachUndoStatement Flyway Teams  After every single successful statement of a migration during Undo
afterEachUndoStatementError Flyway Teams  After every single failed statement of a migration during Undo
afterEachUndo Flyway Teams  After every single successful migration during Undo
afterEachUndoError Flyway Teams  After every single failed migration during Undo
afterUndo Flyway Teams  After successful Undo runs
afterUndoError Flyway Teams  After failed Undo runs
beforeClean Before Clean runs
afterClean After successful Clean runs
afterCleanError After failed Clean runs
beforeInfo Before Info runs
afterInfo After successful Info runs
afterInfoError After failed Info runs
beforeValidate Before Validate runs
afterValidate After successful Validate runs
afterValidateError After failed Validate runs
beforeBaseline Before Baseline runs
afterBaseline After successful Baseline runs
afterBaselineError After failed Baseline runs
beforeRepair Before Repair runs
afterRepair After successful Repair runs
afterRepairError After failed Repair runs


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM