先说说背景,由于在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设置一致的执行效果。