Update : Die aktuelle Spring-Cache-Implementierung verwendet alle Methodenparameter als Cache-Schlüssel, sofern nicht anders angegeben. Wenn Sie ausgewählte Schlüsselverwenden möchten, lesen Sie die Antwort von Arjan, in der die SpEL-Liste verwendet wird. Dies{#isbn, #includeUsed}
ist der einfachste Weg, um eindeutige Schlüssel zu erstellen.
Aus der Frühlingsdokumentation
Die Standardstrategie zur Schlüsselgenerierung wurde mit der Veröffentlichung von Spring 4.0 geändert. Frühere Versionen von Spring verwendeten eine Schlüsselgenerierungsstrategie, bei der für mehrere Schlüsselparameter nur der hashCode () der Parameter und nicht gleich () berücksichtigt wurde. Dies kann zu unerwarteten Schlüsselkollisionen führen (Hintergrund siehe SPR-10237). Der neue 'SimpleKeyGenerator' verwendet für solche Szenarien einen zusammengesetzten Schlüssel.
Vor dem Frühjahr 4.0
Ich empfehle Ihnen, die Werte der Parameter im Spel-Ausdruck mit etwas zu verknüpfen key="#checkWarehouse.toString() + #isbn.toString()")
, das meiner Meinung nach funktionieren sollte, da org.springframework.cache.interceptor.ExpressionEvaluator Object zurückgibt, das später als Schlüssel verwendet wird, damit Sie es nicht angeben müssen ein int
in Ihrem SPEL-Ausdruck.
Der Hash-Code mit einer hohen Kollisionswahrscheinlichkeit kann nicht als Schlüssel verwendet werden.
Jemand in diesem Thread hat vorgeschlagen, zu verwenden, T(java.util.Objects).hash(#p0,#p1, #p2)
aber es wird nicht funktionieren und dieser Ansatz ist leicht zu brechen, zum Beispiel habe ich die Daten von SPR-9377 verwendet :
System.out.println( Objects.hash("someisbn", new Integer(109), new Integer(434)));
System.out.println( Objects.hash("someisbn", new Integer(110), new Integer(403)));
Beide Zeilen drucken -636517714 in meiner Umgebung.
PS Eigentlich in der Referenzdokumentation haben wir
@Cacheable(value="books", key="T(someType).hash(#isbn)")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
Ich denke, dass dieses Beispiel FALSCH und irreführend ist und aus der Dokumentation entfernt werden sollte, da die Schlüssel eindeutig sein sollten.
PPS finden Sie auch unter https://jira.springsource.org/browse/SPR-9036 für einige interessante Ideen zur Standardschlüsselgenerierung.
Ich möchte aus Gründen der Korrektheit und als unterhaltsame Tatsache hinzufügen , dass eine sichere Verwendung von verschlüsselter Hash - Funktion wie SHA256, aufgrund der Eigenschaften solchen Funktion IST für diese Aufgabe möglich, aber es zu berechnen , jedes Mal kann zu teuer sein.
3.1.1
? SPR-9377 wurde behoben für3.1.1
, nein? Könnte jemand einen UPDATED- Abschnitt für diese Antwort hinzufügen ?T(someType).hash(#isbn)
im Frühling3.1.1
?{ #root.methodName, #param1, #param2 }
jedenfalls ist 3.1.1 jetzt eine alte Version.Nach einigen begrenzten Tests mit Spring 3.2 scheint es möglich zu sein, eine Rechtschreibliste zu verwenden :
{..., ..., ...}
. Dies kann auchnull
Werte enthalten. Spring übergibt die Liste als Schlüssel für die eigentliche Cache-Implementierung. Wenn Sie Ehcache verwenden, wird dies irgendwann List # hashCode () aufrufen , das alle seine Elemente berücksichtigt. (Ich bin nicht sicher, ob Ehcache nur auf dem Hash-Code basiert .)Ich verwende dies für einen gemeinsam genutzten Cache, in den ich auch den Methodennamen in den Schlüssel einbinde, den der Spring-Standardschlüsselgenerator nicht enthält . Auf diese Weise kann ich den (einzelnen) Cache leicht löschen, ohne (zu viel ...) das Risiko einzugehen, dass Schlüssel für verschiedene Methoden übereinstimmen. Mögen:
@Cacheable(value="bookCache", key="{ #root.methodName, #isbn?.id, #checkWarehouse }") public Book findBook(ISBN isbn, boolean checkWarehouse) ... @Cacheable(value="bookCache", key="{ #root.methodName, #asin, #checkWarehouse }") public Book findBookByAmazonId(String asin, boolean checkWarehouse) ...
Wenn dies von vielen Methoden benötigt wird und Sie immer alle Parameter für Ihren Schlüssel verwenden, können Sie natürlich auch einen benutzerdefinierten Schlüsselgenerator definieren, der den Klassen- und Methodennamen enthält:
<cache:annotation-driven mode="..." key-generator="cacheKeyGenerator" /> <bean id="cacheKeyGenerator" class="net.example.cache.CacheKeyGenerator" />
...mit:
public class CacheKeyGenerator implements org.springframework.cache.interceptor.KeyGenerator { @Override public Object generate(final Object target, final Method method, final Object... params) { final List<Object> key = new ArrayList<>(); key.add(method.getDeclaringClass().getName()); key.add(method.getName()); for (final Object o : params) { key.add(o); } return key; } }
quelle
{..., ..., ...}
. In der aktuellen Dokumentation heißt es, dass die Standardschlüsselgenerierung alle Parameter berücksichtigt. Also keine Notwendigkeit zu erstellenCacheKeyGenerator
.Sie können einen Spring-EL-Ausdruck verwenden, z. B. für JDK 1.7:
@Cacheable(value="bookCache", key="T(java.util.Objects).hash(#p0,#p1, #p2)")
quelle
@Cacheable(value="books", key="T(someType).hash(#isbn)") public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
- aber es scheint ein falsches und irreführendes Beispiel zu seinSie können die Spring SimpleKey-Klasse verwenden
@Cacheable(value = "bookCache", key = "new org.springframework.cache.interceptor.SimpleKey(#isbn, #checkWarehouse)")
quelle
Das wird funktionieren
@Cacheable(value="bookCache", key="#checkwarehouse.toString().append(#isbn.toString())")
quelle
Benutze das
@Cacheable(value="bookCache", key="#isbn + '_' + #checkWarehouse + '_' + #includeUsed")
quelle