Cache di spring Il metodo @Cacheable viene ignorato quando chiamato dalla stessa class

Sto provando a chiamare un metodo @Cacheable dalla stessa class:

 @Cacheable(value = "defaultCache", key = "#id") public Person findPerson(int id) { return getSession().getPerson(id); } public List findPersons(int[] ids) { List list = new ArrayList(); for (int id : ids) { list.add(findPerson(id)); } return list; } 

e sperando che i risultati di findPersons vengano memorizzati nella cache, ma l’annotazione @Cacheable viene ignorata e il metodo findPerson viene eseguito ogni volta.

Sto facendo qualcosa di sbagliato qui, o questo è destinato?

Ciò è dovuto al modo in cui i proxy vengono creati per gestire la memorizzazione nella cache, funzionalità correlate alle transazioni in spring. Questo è un ottimo riferimento di come lo gestisce Spring – Transactions, Caching e AOP: comprensione dell’utilizzo del proxy in spring

In breve, una chiamata autonoma scavalca il proxy dinamico e qualsiasi preoccupazione trasversale come la memorizzazione nella cache, la transazione ecc. Che fa parte della logica dei proxy dinamici viene anch’essa superata.

La correzione consiste nell’utilizzare il tempo di compilazione di AspectJ o la tessitura del tempo di caricamento.

Ecco cosa faccio per i piccoli progetti con l’utilizzo solo marginale delle chiamate al metodo all’interno della stessa class. La documentazione in codice è fortemente raccomandata, in quanto potrebbe sembrare straziante per i colleghi. Ma è facile da testare, semplice, veloce da raggiungere e mi risparmia la strumentazione completa AspectJ. Tuttavia, per un utilizzo più intenso, consiglierei la soluzione 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 findPersons(int[] ids) { List list = new ArrayList(); for (int id : ids) { list.add(_personDao.findPerson(id)); } return list; } } 

Per chiunque usi il plugin Grails Spring Cache , una soluzione alternativa è descritta nella documentazione . Ho avuto questo problema su un’app di Grails, ma sfortunatamente la risposta accettata sembra essere inutilizzabile per Grails. La soluzione è brutta, IMHO, ma funziona.

Il codice di esempio lo dimostra bene:

 class ExampleService { def grailsApplication def nonCachedMethod() { grailsApplication.mainContext.exampleService.cachedMethod() } @Cacheable('cachedMethodCache') def cachedMethod() { // do some expensive stuff } } 

Basta sostituire exampleService.cachedMethod () con il proprio servizio e metodo.