为何@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.
相关产品推荐
相关产品推荐

