先說說背景,由於在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設置一致的執行效果。