53

我正在尝试@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每次都执行方法。

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

4

3 回答 3

57

这是因为在 Spring 中为处理缓存、事务相关功能创建代理的方式。这是关于 Spring 如何处理它的一个很好的参考 -事务、缓存和 AOP:理解 Spring 中的代理使用

简而言之,自调用绕过了动态代理,并且也绕过了作为动态代理逻辑一部分的缓存、事务等任何横切关注点。

解决方法是使用 AspectJ 编译时间或加载时间编织。

于 2012-08-24T20:22:21.983 回答
29

这是我为在同一个类中仅少量使用方法调用的小型项目所做的。强烈建议使用代码内文档,因为它对同事来说可能看起来很奇怪。但它易于测试、简单、快速实现,并且为我省去了成熟的 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;
    }
}
于 2015-12-04T14:42:45.120 回答
2

对于使用Grails Spring Cache插件的任何人,文档中描述了一种解决方法。我在 grails 应用程序上遇到了这个问题,但不幸的是,接受的答案似乎对 Grails 不可用。恕我直言,解决方案很丑陋,但它有效。

示例代码很好地展示了这一点:

class ExampleService {
    def grailsApplication

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

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

只需将exampleService.cachedMethod()替换为您自己的服务和方法。

于 2013-05-31T19:13:39.547 回答