@AutoConfigureMockMvc致集成测试无限循环栈溢出问题咨询
这个问题和MockMvc本身配置没有关系,是两项变更叠加导致的:
- 属性加载逻辑的执行时机失效:你把依赖属性加载逻辑从测试类的static块迁移到
Application类的main方法后,集成测试启动时根本不会执行main方法——@SpringBootTest是通过Spring测试框架直接启动Spring上下文,不会调用应用的main入口方法,导致依赖需要的系统属性完全没有被设置,触发Web层相关自动配置(包括MockMvc依赖的Servlet配置)初始化失败。 - 日志组件缺陷掩盖了真实异常:Spring Boot 2.5.6默认引入的Logback版本没有做异常链循环引用检测,当Spring初始化失败抛出的异常存在自引用cause链时,Logback的
ThrowableProxy会递归遍历异常栈,无限重复初始化代理对象,最终抛出栈溢出错误,把最开始的配置缺失原始异常完全覆盖。
你观察到移除@SpringBootTest和@AutoConfigureMockMvc后测试正常,本质是因为移除这两个注解后不会触发完整的Web层Spring上下文初始化,那些需要依赖属性的自动配置Bean不会被创建,自然不会触发初始化失败的流程。
按长期可维护性优先级推荐以下方案:
最优方案:通过Spring Boot标准扩展点加载属性
不要把全局属性初始化逻辑绑定在main方法上,应该实现EnvironmentPostProcessor接口完成依赖属性加载,并且在META-INF/spring.factories中注册该扩展点。这种实现可以保证不管是main方法启动应用、还是集成测试启动上下文,都会在属性解析、自动配置Bean初始化之前完成系统属性设置,不会出现多入口启动的逻辑不一致问题。实现示例:
public class DependencyPropertyProcessor implements EnvironmentPostProcessor { @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { PropertiesReader propertiesReader = new PropertiesReader(); propertiesReader.readDependencyProperties().forEach(System::setProperty); } }在
resources/META-INF/spring.factories文件中添加注册配置:org.springframework.boot.env.EnvironmentPostProcessor=你的类全路径.DependencyPropertyProcessor配置完成后,可以删除Application main方法、测试类static块中重复的属性加载逻辑。
临时兼容方案:抽离公共方法多入口调用
如果暂时不想调整为扩展点实现,可以把属性加载逻辑抽为公共静态工具方法,在Application的main方法中调用的同时,恢复测试类中的static块调用该方法,保证测试启动时属性能正常加载。排查辅助技巧:如果后续再遇到类似Logback栈溢出看不到真实异常的场景,可以添加JVM启动参数
-Dlogback.disableThrowableProxy=true,关闭Logback的异常代理功能,就能直接打印出原始的启动报错信息,避免被栈溢出的假象误导。
内容的提问来源于stack exchange,提问作者dinika saxena

