J'essaie d'appeler un @Cacheable
méthode de la même classe:
@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;
}
et en espérant que les résultats de findPersons
sont également mis en cache, mais le @Cacheable
l'annotation est ignorée et la méthode findPerson
est exécutée à chaque fois.
Suis-je en train de faire quelque chose de mal ici, ou c'est prévu?
Cela est dû à la façon dont les proxys sont créés pour gérer la mise en cache, les fonctionnalités liées aux transactions dans Spring. Ceci est une très bonne référence sur la façon dont Spring le gère - Transactions, mise en cache et AOP: comprendre l'utilisation du proxy dans Spring
En bref, un appel automatique contourne le proxy dynamique et tout problème transversal comme la mise en cache, la transaction, etc. qui fait partie de la logique des proxy dynamiques est également contourné.
Le correctif consiste à utiliser le temps de compilation AspectJ ou le tissage du temps de chargement.
Voici ce que je fais pour les petits projets avec une utilisation marginale des appels de méthode dans la même classe. La documentation en code est fortement conseillée, car elle peut sembler étrange à ses collègues. Mais c'est facile à tester, simple, rapide à réaliser et m'épargne la pleine instrumentation AspectJ. Cependant, pour une utilisation plus intensive, je conseillerais la solution 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;
}
}
Pour tous ceux qui utilisent le plug-in Grails Spring Cache , ne solution de contournement est décrite dans la documentation . J'ai eu ce problème sur une application Grails, mais malheureusement, la réponse acceptée semble inutilisable pour Grails. La solution est moche, à mon humble avis, mais cela fonctionne.
L'exemple de code le montre bien:
class ExampleService {
def grailsApplication
def nonCachedMethod() {
grailsApplication.mainContext.exampleService.cachedMethod()
}
@Cacheable('cachedMethodCache')
def cachedMethod() {
// do some expensive stuff
}
}
Remplacez simplement exampleService.cachedMethod () par votre propre service et méthode.