延緩Spring Boot啟動時間直到資料庫啟動的方法和原始碼 - Marten

banq發表於2020-07-02

當使用Spring Boot或僅使用普通的Spring Framework時,可能要延遲應用程式的啟動,直到可以與資料庫建立正確的連線為止。當使用容器技術(例如Docker)時,情況可能更是如此。

DatabaseStartupValidator會延遲應用程式的進一步啟動,直到可以建立與資料庫的連線為止。預設情況下,它將每秒嘗試連線到資料庫,並僅捕獲異常。它將嘗試60秒,此後如果無法建立連線,則失敗(所有這些屬性都是可配置的)。

要使用它,只需宣告一個bean並注入資料來源。您定義一個驗證查詢(從Spring 5.3開始,它將isValid預設使用JDBC 4 方法!)。Spring Boot附帶了一個方便的列舉,該列舉已經包含針對一系列受支援資料庫的預設驗證查詢(由Spring Boot Actuator中的執行狀況檢查使用)。

@SpringBootApplication
public class DatabaseUpApplication {

    public static void main(String[] args) {
        SpringApplication.run(DatabaseUpApplication.class, args);
    }

    @Bean
    public DatabaseStartupValidator databaseStartupValidator(DataSource dataSource) {
        var dsv = new DatabaseStartupValidator();
        dsv.setDataSource(dataSource);
        dsv.setValidationQuery(DatabaseDriver.POSTGRESQL.getValidationQuery());
        return dsv;
    }
}

但是,僅定義此bean可能還不夠,需要更多配置。有許多依賴DataSource 的beans如EntityManagerFactory,Flyway 或 JdbcTemplate ,需要手工增加@DependsOn在這些@Bean方法上:可通過Spring Boot進行一些自動配置,也可以使用a BeanFactoryPostProcessor來修改bean

@Bean
public static BeanFactoryPostProcessor dependsOnPostProcessor() {
    return bf -> {
        // Let beans that need the database depend on the DatabaseStartupValidator
        // like the JPA EntityManagerFactory or Flyway
        String[] flyway = bf.getBeanNamesForType(Flyway.class);
        Stream.of(flyway)
                .map(bf::getBeanDefinition)
                .forEach(it -> it.setDependsOn("databaseStartupValidator"));

        String[] jpa = bf.getBeanNamesForType(EntityManagerFactory.class);
        Stream.of(jpa)
                .map(bf::getBeanDefinition)
                .forEach(it -> it.setDependsOn("databaseStartupValidator"));
    };
}

這裡延緩了Flyway 和 EntityManagerFactory執行,直到DatabaseStartupValidator 完全初始化。

原始碼可以在GitHub找到

相關文章