2015-08-25 1 views
0

I a une méthode pour appeler une autre méthode @Cacheable comme ceci:cache ressort fonctionne w/méthode imbriquée

public ItemDO findMethod2(long itemId) { 
    this.findMethod1(itemId); 
    ... 
} 

@Cacheable(value = "Item", key="#itemId", unless="#result == null") 
public ItemDO findMethod1(long itemId) { 
    ... 
} 

Le cache fonctionne bien si je l'appelle directement la findMethod1(). Cependant, quand j'appelle findMethod2() le cache sur findMethod1() est totalement ignoré.

Pourrait-il être l'astuce faite par JVM qui inline findMethod1() dans findMethod2()?

Est-ce que quelqu'un rencontre un problème similaire?

Merci!

Répondre

4

Ce n'est pas une astuce JVM, c'est-à-dire que findMethod1() n'est pas inséré à l'intérieur de findMethod2() ou quoi que ce soit de cette nature.

Le problème est que votre code est sans passer par le « Proxy » que Spring crée autour de votre classe d'application (contenant findMethod1()) pour l'annotation @Cacheable.

Comme Spring annotations transactionnelles et de l'infrastructure sous-jacente, compte tenu d'une interface, par défaut Spring créera un JDK Dynamic Proxy (style AOP) pour « intercepter » l'appel de méthode et d'appliquer les « conseils » (tel que déterminé par le type d'annotation, dans ce cas, la mise en cache). Cependant, une fois que l'objet cible est appelé depuis l'intercepteur (Proxy) agissant au nom de l'objet cible pour appliquer le conseil, le Thread s'exécute maintenant dans le contexte de l'objet cible afin que toutes les invocations de méthodes directement sur l'objet cible lui-même.

Il ressemble un peu à quelque chose comme ça ...

caller -> Proxy -> findMethod2() -> findMethod1() 

Idéalement ce que vous voulez est ce ...

caller -> Proxy -> findMethod2() -> Proxy -> findMethod1() 

Cependant, le fil est déjà exécuté dans le contexte de la " ciblez l'objet une fois à findMethod2(), de sorte que vous vous retrouvez avec la première pile d'appels.

Le documentaire Spring l'explique mieux here. Le document poursuit en signalant les solutions à ce problème, le plus favorable étant de refactoriser votre code pour vous assurer que l'appelant passe par l'intercepteur Proxy pour l'invocation de la 2ème méthode (c'est-à-dire findMethod1()).

Une autre solution à ce problème serait d'utiliser AspectJ complet, en utilisant un compilateur et un tueur de code octet pendant le processus de construction de l'application pour modifier l'objet cible réel afin que les invocations ultérieures de l'objet cible interceptent et appliquez le conseil en conséquence.

Voir la documentation de printemps sur la trade-offs entre Spring AOP et plein AspectJ, ainsi que how to use full AspectJ dans vos applications de printemps.

Espérons que cela aide.

À la votre!