You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何@ContextHierarchy搭配@EnableConfigurationProperties时不缓存Bean?

问题分析与解决思路

嗨,我来帮你拆解这个问题——你遇到的HelloWorld组件被初始化两次的情况,本质是Spring测试上下文的缓存机制在非@SpringBootTest场景下没正常生效,结合你用到的@EnableConfigurationProperties和@ContextHierarchy,具体原因和解决办法可以这样梳理:

为啥会出现重复初始化?

当你不用@SpringBootTest,手动搭配@EnableConfigurationProperties和@ContextHierarchy时,Spring Test的上下文缓存逻辑会“认不出”这两个测试应该复用同一个上下文:

  • @ContextHierarchy本身是用来构建上下文层级的,但在非Boot场景下,Spring默认的缓存策略会因为两个测试的配置组合细节差异(哪怕看起来一样),或者缺少Boot自动做的缓存优化,而判定需要重新创建上下文。
  • 另外,@EnableConfigurationProperties会引入额外的配置元数据处理逻辑,这会让Spring觉得每个测试的上下文配置是独特的,直接跳过缓存,导致每次测试都重新初始化所有Bean,包括你的HelloWorld,所以会两次输出init666。

而@SpringBootTest能正常工作,是因为它内部已经集成了Boot的上下文缓存优化,会自动处理配置合并、缓存键生成这些细节,确保相同配置的测试复用同一个上下文。

几个可行的解决办法

1. 给测试上下文加统一的缓存标识

你可以通过@TestPropertySource给两个测试类添加相同的自定义属性,让Spring把它们识别为同一个上下文进行缓存:

// 在TestOne和TestTwo上都加上这段配置
@ContextHierarchy({
    @ContextConfiguration(classes = TestConfiguration.class)
})
@TestPropertySource(properties = "test.context.cache.key=shared-hello-world")
@EnableConfigurationProperties
public class TestOne {
    // 你的测试代码
}

这样Spring会把带有这个相同属性的测试上下文视为同一组,自动复用,不会重复初始化Bean。

2. 让配置类继承Spring Boot的配置能力

如果你的测试配置类没有用到Boot的自动配置,可以给TestConfiguration加上@SpringBootConfiguration注解,让Spring Test应用Boot的缓存逻辑:

@SpringBootConfiguration
@EnableConfigurationProperties
public class TestConfiguration {
    // 你的Bean定义
}

之后测试类直接引用这个配置类(如果层级不是必须的,甚至可以去掉@ContextHierarchy),Boot的缓存机制会自动帮你复用上下文。

3. 抽离公共配置,统一测试上下文

如果两个测试的上下文结构差不多,把公共的配置(比如TestConfiguration、HelloWorld的Bean定义)抽成一个共享配置类,让两个测试类完全复用这个配置:

// 公共测试配置类
@Configuration
@EnableConfigurationProperties
public class SharedTestConfig {
    // 把TestConfiguration里的内容移到这里
    @Bean
    public HelloWorld helloWorld() {
        return new HelloWorld();
    }
}

// TestOne
@ContextConfiguration(classes = SharedTestConfig.class)
public class TestOne {
    // 测试代码
}

// TestTwo
@ContextConfiguration(classes = SharedTestConfig.class)
public class TestTwo {
    // 测试代码
}

这种方式消除了两个测试的配置差异,Spring会自动识别并缓存这个共享上下文,自然就不会重复初始化Bean了。

内容的提问来源于stack exchange,提问作者Artem K.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:37:51