Der Spring-Cache funktioniert nicht, wenn die zwischengespeicherte Methode von einer anderen Methode derselben Bean aufgerufen wird.
Hier ist ein Beispiel, um mein Problem klar zu erklären.
Aufbau:
<cache:annotation-driven cache-manager="myCacheManager" />
<bean id="myCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="myCache" />
</bean>
<!-- Ehcache library setup -->
<bean id="myCache"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:shared="true">
<property name="configLocation" value="classpath:ehcache.xml"></property>
</bean>
<cache name="employeeData" maxElementsInMemory="100"/>
Zwischengespeicherter Dienst:
@Named("aService")
public class AService {
@Cacheable("employeeData")
public List<EmployeeData> getEmployeeData(Date date){
..println("Cache is not being used");
...
}
public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){
List<EmployeeData> employeeData = getEmployeeData(date);
...
}
}
Ergebnis:
aService.getEmployeeData(someDate);
output: Cache is not being used
aService.getEmployeeData(someDate);
output:
aService.getEmployeeEnrichedData(someDate);
output: Cache is not being used
Der getEmployeeData
Methodenaufruf verwendet employeeData
erwartungsgemäß den Cache im zweiten Aufruf. Wenn die getEmployeeData
Methode jedoch innerhalb der AService
Klasse (in getEmployeeEnrichedData
) aufgerufen wird , wird der Cache nicht verwendet.
Funktioniert der Spring Cache so oder fehlt mir etwas?
someDate
param?Antworten:
Ich glaube, so funktioniert es. Soweit ich mich erinnere, wurde eine Proxy-Klasse generiert, die alle Anforderungen abfängt und mit dem zwischengespeicherten Wert antwortet, aber 'interne' Aufrufe innerhalb derselben Klasse erhalten den zwischengespeicherten Wert nicht.
Von https://code.google.com/p/ehcache-spring-annotations/wiki/UsingCacheable
quelle
@Cacheable
auf DAO :( Wenn Sie eine bessere Lösung haben, lassen Sie es mich bitte wissen, danke.@Resource
Self-Autowiring gelöst werden , siehe Beispiel stackoverflow.com/a/48867068/907576@Cacheable
Methode sollte seinpublic
, sie funktioniert nicht bei paketprivaten Methoden. Fand es auf die harte Tour.Seit Spring 4.3 konnte das Problem durch Selbstautowire über
@Resource
Annotation gelöst werden :quelle
4.3.17
und es hat nicht funktioniert, Anrufe,self
um nicht durch einen Proxy zu gehen und der Cache wird (noch) umgangen.Das folgende Beispiel ist das, was ich verwende, um den Proxy aus derselben Bean heraus zu treffen. Es ähnelt der Lösung von @ mario-eis, finde es aber etwas lesbarer (vielleicht nicht :-). Wie auch immer, ich möchte die @ Cache-Anmerkungen auf dem Service-Level halten:
Siehe auch Neue Transaktion in Spring Bean starten
quelle
applicationContext.getBean(SettingService.class);
ist beispielsweise das Gegenteil von Abhängigkeitsinjektion. Ich schlage vor, diesen Stil zu vermeiden.Folgendes mache ich für kleine Projekte mit nur geringfügiger Verwendung von Methodenaufrufen innerhalb derselben Klasse. In-Code-Dokumentation wird dringend empfohlen, da sie für Kollegen möglicherweise unangemessen ist. Aber es ist einfach zu testen, einfach, schnell zu erreichen und erspart mir die volle AspectJ-Instrumentierung. Für eine stärkere Nutzung würde ich jedoch die AspectJ-Lösung empfehlen.
quelle
In meinem Fall füge ich Variable hinzu:
Also rufe ich die
getEmployeeData
Methode mit dem aufaService
}}
In diesem Fall wird der Cache verwendet.
quelle
Verwenden Sie statisches Weben, um einen Proxy um Ihre Bohne zu erstellen. In diesem Fall würden sogar 'interne' Methoden korrekt funktionieren
quelle
<iajc
Compiler (von ant), der alle notwendigen Aspekte für cachefähige Klassen auflöst.Ich benutze interne innere Bean (
FactoryInternalCache
) mit echtem Cache für diesen Zweck:quelle
Die mit Abstand einfachste Lösung besteht darin, einfach so zu referenzieren:
quelle