从同一类中调用时,Spring 缓存 @Cacheable 方法被忽略
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12115996/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring cache @Cacheable method ignored when called from within the same class
提问by David Zhao
I'm trying to call a @Cacheablemethod from within the same class:
我正在尝试@Cacheable从同一个类中调用一个方法:
@Cacheable(value = "defaultCache", key = "#id")
public Person findPerson(int id) {
return getSession().getPerson(id);
}
public List<Person> findPersons(int[] ids) {
List<Person> list = new ArrayList<Person>();
for (int id : ids) {
list.add(findPerson(id));
}
return list;
}
and hoping that the results from findPersonsare cached as well, but the @Cacheableannotation is ignored, and findPersonmethod got executed everytime.
并希望结果findPersons也被缓存,但@Cacheable注释被忽略,并且findPerson方法每次都被执行。
Am I doing something wrong here, or this is intended?
我在这里做错了什么,还是有意为之?
回答by Biju Kunjummen
This is because of the way proxies are created for handling caching, transaction related functionality in Spring. This is a very good reference of how Spring handles it - Transactions, Caching and AOP: understanding proxy usage in Spring
这是因为在 Spring 中创建代理以处理缓存、事务相关功能的方式。这是 Spring 如何处理它的一个很好的参考 -事务、缓存和 AOP:了解 Spring 中的代理使用
In short, a self call bypasses the dynamic proxy and any cross cutting concern like caching, transaction etc which is part of the dynamic proxies logic is also bypassed.
简而言之,自我调用绕过了动态代理,并且作为动态代理逻辑一部分的任何横切关注点(如缓存、事务等)也被绕过。
The fix is to use AspectJ compile time or load time weaving.
修复方法是使用 AspectJ 编译时或加载时编织。
回答by Mario Eis
Here is what I do for small projects with only marginal usage of method calls within the same class. In-code documentation is strongly advidsed, as it may look strage to colleagues. But its easy to test, simple, quick to achieve and spares me the full blown AspectJ instrumentation. However, for more heavy usage I'd advice the AspectJ solution.
以下是我为在同一类中仅少量使用方法调用的小型项目所做的工作。强烈建议代码中的文档,因为它可能看起来很奇怪同事。但它易于测试、简单、快速实现,并且让我无需使用完整的 AspectJ 工具。但是,对于更频繁的使用,我建议使用 AspectJ 解决方案。
@Service
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class PersonDao {
private final PersonDao _personDao;
@Autowired
public PersonDao(PersonDao personDao) {
_personDao = personDao;
}
@Cacheable(value = "defaultCache", key = "#id")
public Person findPerson(int id) {
return getSession().getPerson(id);
}
public List<Person> findPersons(int[] ids) {
List<Person> list = new ArrayList<Person>();
for (int id : ids) {
list.add(_personDao.findPerson(id));
}
return list;
}
}
回答by Dónal Boyle
For anyone using the Grails Spring Cacheplugin, a workaround is described in the documentation. I had this issue on a grails app, but unfortunately the accepted answer seems to be unusable for Grails. The solution is ugly, IMHO, but it works.
对于使用Grails Spring Cache插件的任何人,文档中描述了一种解决方法。我在 grails 应用程序上遇到了这个问题,但不幸的是,接受的答案似乎对 Grails 不可用。恕我直言,解决方案很难看,但它有效。
The example code demonstrates it well:
示例代码很好地展示了它:
class ExampleService {
def grailsApplication
def nonCachedMethod() {
grailsApplication.mainContext.exampleService.cachedMethod()
}
@Cacheable('cachedMethodCache')
def cachedMethod() {
// do some expensive stuff
}
}
Simply replace exampleService.cachedMethod()with your own service and method.
只需将exampleService.cachedMethod()替换为您自己的服务和方法。

