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

为何@Bean返回mock()时@Cacheable生效,使用@MockBean时不生效?

两种写法下@Cacheable表现差异的核心原因

@Cacheable的缓存逻辑依赖Spring AOP动态代理实现,只有调用经过Spring代理的Bean实例时,缓存切面才会被触发执行。两种Mock写法的差异本质是生成的Mock实例是否被Spring缓存代理包裹。

第一种写法(手动@TestConfiguration注册Mock Bean)缓存正常的原因

你通过@TestConfiguration手动将Mock对象注册为Spring Bean时,该对象会走完整的Spring Bean生命周期处理流程:如果类/方法标记了@Cacheable等缓存注解,Spring会自动为该Mock实例织入缓存切面,生成对应的代理对象。
你@Autowired注入的serviceXY本质是被代理过的实例,调用methodThatFillsCache方法时会先走代理的缓存逻辑,Mock方法返回结果后会被代理自动写入缓存,因此缓存可以正常填充。
对应代码:

@Autowired
ServiceXY serviceXY

@TestConfiguration
static class AppDefCachingTestConfiguration {
    @Bean
    public ServiceXY ServiceXYMock() {
        return mock(ServiceXY.class);
    }
}

第二种写法(@MockBean注解)缓存失效的原因

Spring Boot提供的@MockBean注解的核心作用是直接替换Spring上下文中对应类型的原始Bean,它生成的Mock实例会跳过常规Bean的AOP代理织入流程,你注入的serviceXY就是纯Mock对象本身,没有被缓存代理包裹。
调用它的methodThatFillsCache方法时不会触发任何缓存切面逻辑,自然不会往缓存中写入任何值,你后续从缓存中获取TEST1这个key时拿到的是null,调用equals方法就会抛出NullPointerException。
对应代码:

@MockBean
ServiceXY serviceXY

出问题的测试代码:

@Autowired
ConcurrentMapCacheManager cmcm; 

@Test
void anTest(){
when(serviceXY.methodThatFillsCache(anyString()).thenReturn("ABC");

serviceXY.methodThatFillsCache("TEST1");

// 此处cmcm.getCache("Cachename").get("TEST1",String.class)返回null,调用equals触发NPE
cmcm.getCache("Cachename").get("TEST1",String.class).equals("ABC");
...
}

内容的提问来源于stack exchange,提问作者Nico S.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 14:06:03