Spring Boot升级至3.1.1后集成测试出现flywayInitializer Bean创建异常
问题详情
将Spring Boot及相关依赖(含spring-boot-starter-test)从2.2.4.RELEASE升级至3.1.1后,运行集成测试时出现Bean创建失败错误:
创建类路径资源[com/freit/medicalservice/config/CustomFlywayConfiguration.class]中定义的名为
flywayInitializer的Bean失败。
完整异常栈显示,执行版本为1.1.13 - Rename Logo Files To Header Files的数据库迁移时触发NullPointerException,根源是com.freit.medicalservice.config.SpringContext.context为空,调用ApplicationContext.getBean时出错。
相关代码与配置
- 自定义Flyway配置类:
@Configuration class CustomFlywayConfiguration extends FlywayAutoConfiguration.FlywayConfiguration { @DependsOn("springContext") public FlywayMigrationInitializer flywayInitializer(Flyway flyway) { return super.flywayInitializer(flyway, null); } }
- Flyway配置(
.properties):
spring.flyway.locations=classpath:db/migration,classpath:/db/test_data,classpath:/db_scripts,com/freit/medicalservice/common/migrations spring.flyway.enabled=true spring.flyway.baseline-on-migrate=true spring.flyway.validate-on-migrate=true
- 测试类注解:
@SpringBootTest @AutoConfigureMockMvc @Transactional @ActiveProfileTest
原因分析
- Spring Boot 3.x Flyway自动配置变更:
FlywayAutoConfiguration.FlywayConfiguration的内部逻辑在3.x版本中发生调整,继承该类的自定义配置方式不再适配,@DependsOn("springContext")无法保证springContextBean在Flyway初始化前完成加载。 - 静态上下文持有风险:迁移脚本中依赖的
SpringContext通过静态字段持有ApplicationContext,在Spring Boot 3.x的测试生命周期中,Flyway迁移执行时机提前,导致静态上下文还未被初始化就被调用。
修复方案
1. 重构自定义Flyway配置
放弃继承FlywayAutoConfiguration.FlywayConfiguration,直接注册FlywayMigrationInitializer并管理依赖:
@Configuration public class CustomFlywayConfiguration { @Bean @DependsOn("springContext") public FlywayMigrationInitializer flywayInitializer(Flyway flyway) { return new FlywayMigrationInitializer(flyway, null); } }
2. 修正SpringContext的上下文持有方式
将SpringContext改为实现ApplicationContextAware的Spring组件,确保上下文被正确注入:
@Component public class SpringContext implements ApplicationContextAware { private static ApplicationContext context; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { context = applicationContext; } public static <T> T getBean(Class<T> beanClass) { return context.getBean(beanClass); } // 按需添加其他getBean重载方法 }
确保该类被Spring扫描到(放在组件扫描路径下)。
3. 调整迁移脚本依赖逻辑(可选)
如果迁移脚本必须依赖Spring Bean,建议将相关逻辑从Flyway脚本中移出,改用Spring的ApplicationListener<ContextRefreshedEvent>或CommandLineRunner,在Spring上下文完全初始化后执行数据操作。
4. 检查测试注解配置
- 确认
@ActiveProfileTest是有效的自定义注解,对应的测试环境配置文件能正确加载,无Flyway配置冲突。 - Spring Boot 3.x中
@Transactional在集成测试中的事务提交/回滚逻辑有细微调整,确保其不会干扰Flyway的初始化流程。
内容的提问来源于stack exchange,提问作者Ali Azlan

