从同一个类中调用时,忽略Spring缓存@Cacheable方法

时间:2012-08-24 20:11:40

标签: spring caching spring-cache

我正在尝试从同一个类中调用@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;
}

并希望findPersons的结果也被缓存,但忽略@Cacheable注释,并且每次都执行findPerson方法。

我在这里做错了什么,或者这是有意的吗?

3 个答案:

答案 0 :(得分:38)

这是因为创建代理的方式是为了处理Spring中的缓存和事务相关的功能。这是Spring如何处理它的非常好的参考 - Transactions, Caching and AOP: understanding proxy usage in Spring

简而言之,自我调用会绕过动态代理,并且还会绕过作为动态代理逻辑一部分的任何交叉问题,如缓存,事务等。

修复方法是使用AspectJ编译时或加载时编织。

答案 1 :(得分:14)

以下是我对同一类中只有少量方法调用的小项目所做的工作。强烈建议使用代码内文档,因为它可能会让同事感到惊讶。但它易于测试,简单,快速实现,并使我完全成熟的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;
    }
}

答案 2 :(得分:2)

对于使用 Grails Spring Cache 插件的任何人,a workaround is described in the documentation。我在grails应用程序上遇到了这个问题,但不幸的是,接受的答案似乎对Grails无法使用。解决方案是丑陋的,恕我直言,但它的确有效。

示例代码演示得很好:

class ExampleService {
    def grailsApplication

    def nonCachedMethod() {
        grailsApplication.mainContext.exampleService.cachedMethod()
    }

    @Cacheable('cachedMethodCache')
    def cachedMethod() {
        // do some expensive stuff
    }
}

只需使用您自己的服务和方法替换 exampleService.cachedMethod()