Spring缓存@Cacheable:从同一bean的另一个方法调用时无法工作

187

当从同一Bean的另一个方法调用缓存方法时,Spring缓存就不起作用了。

这里有一个例子来清楚地解释我的问题。

配置:

<cache:annotation-driven cache-manager="myCacheManager" />

<bean id="myCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
    <property name="cacheManager" ref="myCache" />
</bean>

<!-- Ehcache library setup -->
<bean id="myCache"
    class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:shared="true">
    <property name="configLocation" value="classpath:ehcache.xml"></property>
</bean>

<cache name="employeeData" maxElementsInMemory="100"/>  

已缓存的服务:

@Named("aService")
public class AService {

    @Cacheable("employeeData")
    public List<EmployeeData> getEmployeeData(Date date){
    ..println("Cache is not being used");
    ...
    }

    public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){
        List<EmployeeData> employeeData = getEmployeeData(date);
        ...
    }

}

结果:

aService.getEmployeeData(someDate);
output: Cache is not being used
aService.getEmployeeData(someDate); 
output: 
aService.getEmployeeEnrichedData(someDate); 
output: Cache is not being used

getEmployeeData方法的第二个调用使用了缓存employeeData,这是预期的。但是当在AService类中(在getEmployeeEnrichedData中)调用getEmployeeData方法时,缓存没有被使用。

这是Spring缓存的工作方式吗?还是我漏掉了什么?


你是否使用相同的值作为 someDate 参数? - Dewfy
@Dewfy 是的,它是相同的。 - Bala
15个回答

1
使用静态编织来创建围绕您的bean的代理。在这种情况下,即使是“内部”方法也可以正确工作。

什么是“静态织入”?谷歌并没有提供太多帮助。有什么指导可以理解这个概念吗? - Bala
@Bala - 举个例子,我们项目中使用的是<iajc编译器(来自ant),它解决了所有可缓存类的必要方面。 - Dewfy

0

我想分享我认为最简单的方法:

  • 自动装配控制器并使用它来调用方法,而不是使用类上下文this

更新后的代码如下:

@Controller
public class TestController {


    @Autowired TestController self;

    @RequestMapping("/test")
    public String testView(){
        self.expensiveMethod();
        return "test";
    }


    @Cacheable("ones")
    public void expensiveMethod(){
       System.out.println("Cache is not being used");
    }

}

0

这就是它的工作原理。 将您的缓存方法移动到帮助器/包装组件bean中。


0

处理缓存注释的默认建议模式是“代理”。在应用程序启动时,所有缓存注释(如@Caching、@Cacheable、@CacheEvict等)都会被扫描,并为所有这些类生成目标代理类。代理允许拦截对这些可缓存方法的调用,从而添加缓存建议/行为。

因此,当我们从同一类中调用可缓存方法时,客户端的调用不会以允许添加缓存建议的方式被拦截。因此,每次都会出现意外的缓存未命中。

解决方案:从不同的bean中调用Cacheable方法,以使用带有缓存建议的代理类。


1
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

0

基于单一职责原则的实现;可缓存类仅支持缓存而不使用缓存 ;-).


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接