[SprintBoot]Flyway與Shiro加載衝突解決探討

         先說說背景,由於在SprintBoot項目裏引入了Shiro,並希望引入Flyway來管理數據庫遷移,會有加載先後順序問題,最終導致Shiro初始化Configuration時,需要查詢數據庫,需要MybatisPlus Mapper加載而報表不存在的錯誤,如果表已存在則不存在此問題:

bad SQL grammar []; nested exception is org.postgresql.util.PSQLException: ERROR: relation "d_resource" does not exist
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:655)
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:635)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338)
	

網上多是說,通過三步來達到目的:

  1) 禁用Flyway自動配置加載:

        在註解@SpringBootApplication中排除掉FlywayAutoConfiguration的加載:

@SpringBootApplication(exclude = {FlywayAutoConfiguration.class})
public class ExampleApplication {

2) 手動配置FlywayConfig(依據網上出處):

@Configuration
@Slf4j
public class FlywayConfig {
 
    @Autowired
    private DataSource dataSource; 
 
    @PostConstruct
    public void migrate() {
        Flyway flyway = Flyway.configure()
                .dataSource(dataSource)
                .baselineOnMigrate(true)
                .load();
 
        try {
            flyway.migrate();
        } catch (FlywayException e) {
            flyway.repair();
            log.error("Flyway配置出錯",e);
        }
    }
}

3)依賴加持

    在Shiro或Mybatis 的Config中加入@DependsOn("flywayConfig"),這樣可控制優先級,比如ShiroConfig,可加在類上:

@Configuration
@DependsOn("flywayConfig")
public class ShiroConfig {

   因爲,這裏ShiroConfig會優先加載,通過Service讀取數據庫數據時,表還不存在而報錯。   

  或者設置了分頁插件的MybatisPlusConfig:

@Configuration
@DependsOn("flywayConfig")
public class MybatisPlusConfig {

    /**
     * 分頁插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        // 設置sql的limit爲無限制,默認是500
        return new PaginationInterceptor().setLimit(-1);
    }
}

   網上有說,可將@DependsOn註解加到部分@Bean註解一起,貌似加類上也是可以達到目的,經過測試發現也是可以的,所以就不用每個@Bean方法上都加,除非需要細粒度控制加載順序。

 

最後,但是

  經過測試,發現,自定義的FlywayConfig,無法正確讀取application.yml裏的配置,比如:

spring
  flyway:
    enabled: true
    baseline-on-migrate: true
    locations: classpath:db/migration,classpath:db/mock

locations的值,始終是默認的db/migration,甚至enabled設置爲false,Flyway仍舊會執行。

由於沒有花大量時間去研究,相信應該有更優解,暫採用了比較笨的辦法解決:

@Slf4j
@Configuration
public class FlywayConfig {

    @Autowired
    private DataSource dataSource;
    // @Autowired
    // private FlywayProperties properties; //FIXME 貌似無法注入

    @Value("${spring.flyway.locations}")
    private List<String> locations = new ArrayList(Collections.singletonList("classpath:db/migration"));

    @Value("${spring.flyway.baseline-on-migrate}")
    private boolean baselineOnMigrate;

    @PostConstruct
    public void migrate() {
        Flyway flyway = Flyway.configure()
                .dataSource(dataSource)
                .locations(locations.toArray(new String[0]))
                .baselineOnMigrate(baselineOnMigrate)
                .load();
        // try {
        flyway.migrate();
        // } catch (FlywayException e) {
        //     flyway.repair();
        //     log.error(e.getMessage(), e);
        // }
    }}

   即顯式的讀取yml中的參數配置,並設置到Flyway引擎中,最終方可達到與yml設置一致的執行效果。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章