I Soluzione di caching basata su SpringCache
1.1 Introduzione a SpringCache
springcache è stato introdotto con spring3.1; incapsula e astrae l'uso della cache, consentendo di ottenere risultati dalla cache semplicemente usando annotazioni sui metodi. Proprio grazie alle annotazioni, risolve il problema dell'accoppiamento tra codice applicativo e codice della cache: permette al codice esistente di supportare immediatamente la cache senza intervenire sul codice applicativo, rendendone l'uso trasparente agli sviluppatori.
1.2 Panoramica di SpringCache
Esistono molti framework di caching, ciascuno con i propri vantaggi, come Redis, Memcached, Guava, Caffeine e così via.
Se il nostro programma vuole usare la cache, deve accoppiarsi a questi framework. Gli architetti più accorti usano già le interfacce per ridurre l'accoppiamento, sfruttando l'astrazione e il polimorfismo della programmazione orientata agli oggetti per separare il codice applicativo dai framework specifici.
Ma dobbiamo comunque chiamare esplicitamente nel codice le interfacce e i metodi relativi alla cache, inserirvi i dati al momento opportuno e leggerli dalla cache al momento opportuno. Pensiamo a 「AOP」 nei relativi scenari di utilizzo, non è proprio un compito naturalmente adatto ad AOP?
A partire da Spring
3.1, è disponibile il supporto della cache tramite annotazioni, analogo alla gestione delle transazioni tramite l'annotazione [@Transactional](/Transactional ), insieme a un'astrazione della cache; in precedenza, lo si implementava generalmente tramite AOP。
Vantaggi dell'utilizzo di Spring Cache:
-
Fornisce un'astrazione di base della Cache, facilitando il passaggio tra diverse implementazioni sottostanti della Cache;
-
Tramite l’annotazione Cache è possibile applicare in modo trasparente la logica di caching al nostro codice applicativo, in modo simile alle transazioni, scrivendo meno codice;
-
Garantire che anche la cache venga ripristinata automaticamente quando si esegue il rollback di una transazione;
-
Supporta logiche di gestione della cache piuttosto complesse;

1.3 Progettazione fondamentale di Spring Cache
A partire da Spring 3.1 è stato introdotto Spring Cache, ossia l'astrazione della cache di Spring. Definendo org.springframework.cache.Cache e org.springframework.cache.CacheManager l'interfaccia per uniformare le diverse tecnologie di cache e supportare l'uso delle annotazioni JCache per semplificare lo sviluppo.
L’interfaccia Cache definisce le specifiche dei componenti della cache e comprende l’insieme delle relative operazioni. Per l’interfaccia Cache, Spring fornisce varie xxxCache implementazione di: RedisCache , EhCacheCache , ConcurrentMapCache ecc.
Esaminiamo parte del codice sorgente per comprendere l'interfaccia Cache e CacheManager interfaccia.
Interfaccia Cache
public interface Cache { //Cache名称 String getName(); //Cache负责缓存的对象 Object getNativeCache(); /** * 获取key对应的ValueWrapper * 没有对应的key,则返回null * key对应的value是null,则返回null对应的ValueWrapper */ @Nullable Cache.ValueWrapper get(Object key); //返回key对应type类型的value @Nullable <T> T get(Object key, @Nullable Class<T> type); //返回key对应的value,没有则缓存Callable::call,并返回 @Nullable <T> T get(Object key, Callable<T> valueLoader); //缓存目标key-value(替换旧值),不保证实时性 void put(Object key, @Nullable Object value); //插入缓存,并返回该key对应的value;先调用get,不存在则用put实现 @Nullable default Cache.ValueWrapper putIfAbsent(Object key, @Nullable Object value) { Cache.ValueWrapper existingValue = this.get(key); if (existingValue == null) { this.put(key, value); } return existingValue; } //删除缓存,不保证实时性 void evict(Object key); //立即删除缓存:返回false表示剔除前不存在制定key活不确定是否存在;返回true,表示该key之前存在 default boolean evictIfPresent(Object key) { this.evict(key); return false; } //清除所有缓存,不保证实时性 void clear(); //立即清楚所有缓存,返回false表示清除前没有缓存或不能确定是否有;返回true表示清除前有缓存 default boolean invalidate() { this.clear(); return false; } public static class ValueRetrievalException extends RuntimeException { @Nullable private final Object key; public ValueRetrievalException(@Nullable Object key, Callable<?> loader, Throwable ex) { super(String.format("Value for key '%s' could not be loaded using '%s'", key, loader), ex); this.key = key; } @Nullable public Object getKey() { return this.key; } } //缓存值的一个包装器接口,实现类为SimpleValueWrapper @FunctionalInterface public interface ValueWrapper { @Nullable Object get(); } }
Come si può vedere, l'interfaccia Cache astrae le operazioni relative alla cache, come get, put ed evict.
Classe astratta AbstractValueAdaptingCache
public abstract class AbstractValueAdaptingCache implements Cache { //是否允许Null值 private final boolean allowNullValues; protected AbstractValueAdaptingCache(boolean allowNullValues) { this.allowNullValues = allowNullValues; } public final boolean isAllowNullValues() { return this.allowNullValues; } @Nullable public ValueWrapper get(Object key) { return this.toValueWrapper(this.lookup(key)); } @Nullable public <T> T get(Object key, @Nullable Class<T> type) { //查询到的缓存值做fromStoreValue转换 Object value = this.fromStoreValue(this.lookup(key)); //转换后非null值且无法转换为type类型则抛出异常 if (value != null && type != null && !type.isInstance(value)) { throw new IllegalStateException("Cached value is not of required type [" + type.getName() + "]: " + value); } else { return value; } } //从缓存中获取key对应的value,子类实现 @Nullable protected abstract Object lookup(Object key); //对于从缓存中获取的值,允许为空且值为NullValue时,处理为null @Nullable protected Object fromStoreValue(@Nullable Object storeValue) { return this.allowNullValues && storeValue == NullValue.INSTANCE ? null : storeValue; } //对于要插入缓存的null值,在允许null值的情况下处理为NullValue;否则抛出异常IllegalArgumentException protected Object toStoreValue(@Nullable Object userValue) { if (userValue == null) { if (this.allowNullValues) { return NullValue.INSTANCE; } else { throw new IllegalArgumentException("Cache '" + this.getName() + "' is configured to not allow null values but null was provided"); } } else { return userValue; } } //get操作依据,查询到缓存值非null,则fromStoreValue转换后包装成SimpleValueWrapper返回 @Nullable protected ValueWrapper toValueWrapper(@Nullable Object storeValue) { return storeValue != null ? new SimpleValueWrapper(this.fromStoreValue(storeValue)) : null; } }
Classe astratta AbstractValueAdaptingCache Implementa l’interfaccia Cache e astrae principalmente la logica di gestione dei valori NULL.
-
allowNullValuesLa proprietà indica se è consentito gestire la memorizzazione nella cache di valori NULL -
fromStoreValuedel metodo per gestire i valori NULLgetoperazione, nella proprietàallowNullValuesquando è true, tratta NullValue come NULL -
toStoreValuemetodo per gestire i valori NULLputoperazione, nella proprietàallowNullValuesSe è true, NULL viene trattato come NullValue, altrimenti viene sollevata un'eccezione -
toValueWrapperil metodo fornisceCachenell'interfacciagetL’implementazione predefinita del metodo legge il valore dalla cache, quindi tramitefromStoreValueconvertito, infine incapsulato comeSimpleValueWrapperrestituisce -
ValueWrapper get(Object key)eT get(Object key, @Nullable Classtype)il metodo è implementato sulla base del metodo precedente -
ValueWrapper get(Object key)e@Nullable Classtype)il metodo è implementato sulla base del metodo precedente -
lookupIl metodo astratto serve a consentire alle sottoclassi di ottenere il valore effettivo della cache
ConcurrentMapCache
public class ConcurrentMapCache extends AbstractValueAdaptingCache { private final String name; //定义ConcurrentMap缓存 private final ConcurrentMap<Object, Object> store; //如果要缓存的是值对象的copy,则由此序列化代理类处理 @Nullable private final SerializationDelegate serialization; public ConcurrentMapCache(String name) { this(name, new ConcurrentHashMap(256), true); } //默认允许处理null public ConcurrentMapCache(String name, boolean allowNullValues) { this(name, new ConcurrentHashMap(256), allowNullValues); } //默认serialization = null public ConcurrentMapCache(String name, ConcurrentMap<Object, Object> store, boolean allowNullValues) { this(name, store, allowNullValues, (SerializationDelegate)null); } protected ConcurrentMapCache(String name, ConcurrentMap<Object, Object> store, boolean allowNullValues, @Nullable SerializationDelegate serialization) { super(allowNullValues); Assert.notNull(name, "Name must not be null"); Assert.notNull(store, "Store must not be null"); this.name = name; this.store = store; this.serialization = serialization; } //serialization不为空,缓存值对象的copy public final boolean isStoreByValue() { return this.serialization != null; } public final String getName() { return this.name; } public final ConcurrentMap<Object, Object> getNativeCache() { return this.store; } //实现lookup:store#get @Nullable protected Object lookup(Object key) { return this.store.get(key); } //基于ConcurrentMap::computeIfAbsent方法实现;get和put的值由fromStoreValue和toStoreValue处理Null @Nullable public <T> T get(Object key, Callable<T> valueLoader) { return this.fromStoreValue(this.store.computeIfAbsent(key, (k) -> { try { return this.toStoreValue(valueLoader.call()); } catch (Throwable var5) { throw new ValueRetrievalException(key, valueLoader, var5); } })); } public void put(Object key, @Nullable Object value) { this.store.put(key, this.toStoreValue(value)); } @Nullable public ValueWrapper putIfAbsent(Object key, @Nullable Object value) { Object existing = this.store.putIfAbsent(key, this.toStoreValue(value)); return this.toValueWrapper(existing); } public void evict(Object key) { this.store.remove(key); } public boolean evictIfPresent(Object key) { return this.store.remove(key) != null; } public void clear() { this.store.clear(); } public boolean invalidate() { boolean notEmpty = !this.store.isEmpty(); this.store.clear(); return notEmpty; } protected Object toStoreValue(@Nullable Object userValue) { Object storeValue = super.toStoreValue(userValue); if (this.serialization != null) { try { return this.serialization.serializeToByteArray(storeValue); } catch (Throwable var4) { throw new IllegalArgumentException("Failed to serialize cache value '" + userValue + "'. Does it implement Serializable?", var4); } } else { return storeValue; } } protected Object fromStoreValue(@Nullable Object storeValue) { if (storeValue != null && this.serialization != null) { try { return super.fromStoreValue(this.serialization.deserializeFromByteArray((byte[])((byte[])storeValue))); } catch (Throwable var3) { throw new IllegalArgumentException("Failed to deserialize cache value '" + storeValue + "'", var3); } } else { return super.fromStoreValue(storeValue); } } }
ConcurrentMapCache estende la classe astratta AbstractValueAdaptingCache , è l'implementazione predefinita della cache di Spring. Supporta la memorizzazione di copie degli oggetti nella cache; SerializationDelegate
serialization gestisce la serializzazione e il valore predefinito è null, ossia una cache basata su riferimenti. Le operazioni relative alla cache si basano sulla classe base AbstractValueAdaptingCache per la gestione dei valori
null, consentiti per impostazione predefinita.
CacheManager
public interface CacheManager { @Nullable //获取指定name的Cache,可能延迟创建 Cache getCache(String name); //获取当前CacheManager下的Cache name集合 Collection<String> getCacheNames(); }
CacheManager gestisce un gruppo di Cache in base a
name. Naturalmente, CacheManager ha anche molte classi di implementazione, come ConcurrentMapCacheManager 、 AbstractCacheManager e SimpleCacheManager , questi xxxCacheManager Le classi servono tutte a definire le regole di gestione di Cache, quindi qui non approfondiremo ulteriormente.
II Utilizzare SpringCache
2.1 Modalità d’uso
Spring Cache è proprio un framework di questo tipo. Sfrutta l’AOP per implementare funzionalità di cache basate sulle annotazioni e offre un’astrazione ben concepita: il codice applicativo non deve preoccuparsi di quale framework di cache venga usato ai livelli sottostanti; basta aggiungere una semplice annotazione per ottenere la funzionalità di cache.
Aggiungere le dipendenze
<!--springboot的cache支持--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <!--配置拓展还需添加的依赖--> <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> <version>2.9.2</version> </dependency>
Configurare la cache
Aggiungere l'annotazione @EnableCaching alla classe di avvio Application
@SpringBootApplication @MapperScan("com.xxxx.dao") @EnableCaching public class AxxxxApplication { public static void main(String[] args) { SpringApplication.run(AxxxxApplication.class, args); } }
Configurare il tipo di cache; qui viene presentata principalmente la cache locale
//方式一:ConcurrentMapCache (不好设置过期时间) @Configuration public class SpringCachingConfig { @Bean public CacheManager cacheManager() { SimpleCacheManager cacheManager = new SimpleCacheManager(); Set<ConcurrentMapCache> mapCaches=new HashSet<>(); //配置cache类型与目录 mapCaches.add(new ConcurrentMapCache("cacheNames1")); mapCaches.add(new ConcurrentMapCache("cacheNames2")); mapCaches.add(new ConcurrentMapCache("cacheNames3")); mapCaches.add(new ConcurrentMapCache("cacheNames4")); cacheManager.setCaches(mapCaches); cacheManager.afterPropertiesSet(); return cacheManager; } } //方式二:CaffeineCache (可设置过期时间) @Configuration public class SpringCachingConfig { @Bean public CacheManager cacheManager() { SimpleCacheManager cacheManager = new SimpleCacheManager(); List<CaffeineCache> caffeineCaches = new ArrayList<>(); //SysConstants.CACHE_NAMES=new ArrayList( //Arrays.asList("cacheNames1","cacheNames2","cacheNames3","cacheNames4") //); for (String cacheName: SysConstants.CACHE_NAMES) { caffeineCaches.add(new CaffeineCache(cacheName, Caffeine.newBuilder() .initialCapacity(50) .maximumSize(30000)//最大存储数量 .expireAfterWrite(2, TimeUnit.HOURS)//过期时间2 小时 .build())); } cacheManager.setCaches(caffeineCaches); return cacheManager; } } //方式三。。。。还可以配置redis以及其他的方式,这里主要介绍以上两种方式
Implementare la cache dell'interfaccia
//控制器1 @RestController @RequestMapping("/path1") @Cacheable(cacheNames = "cacheNames1" ,key="#root.methodName+#a0" ) public class Controller1 { } //控制器2 @RestController @RequestMapping("/path2") @Cacheable(cacheNames = "cacheNames2" ,key="#root.methodName+#a0" ) public class Controller2 { } //控制器3 @RestController @RequestMapping("/path3") @Cacheable(cacheNames = "cacheNames3" ,key="#root.methodName+#a0" ) public class Controller3 { } //控制器4 @RestController @RequestMapping("/path4") @Cacheable(cacheNames = "cacheNames4" ,key="#root.methodName+#a0" ) public class Controller4 { }
2.2 Spiegazione dettagliata delle annotazioni SpringCache
Annotazione @Cacheable
Se il dato non è nella cache: interrogare il database, memorizzarlo nella cache, restituire il risultato,
Se il dato è presente nella cache: restituire direttamente il risultato
| Parametri | Spiegazione | esempio |
| value | Nome della cache, definito nel file di configurazione spring ; è necessario specificarne almeno uno |
Per esempio: @Cacheable(value=”mycache”) @Cacheable(value={”cache1”,”cache2”} |
| key | La key della cache può essere vuota; se specificata, deve essere scritta come espressione SpEL; se non viene specificata, per impostazione predefinita viene composta usando tutti i parametri del metodo | @Cacheable(value=”testcache”,key=”#userName”) |
| condition | Condizione per la memorizzazione nella cache, può essere vuota ed è scritta in SpEL; restituisce true oppure false, e la memorizzazione avviene solo se è true | @Cacheable(value=”testcache”,condition=”#userName.length()>2”) |
Funzione: consente di scrivere nella cache, memorizzandovi il risultato affinché le chiamate successive possano restituire direttamente il valore presente nella cache senza eseguire nuovamente il metodo effettivo. Nell'utilizzo più semplice, nome dell'annotazione=nome della cache, come nell'esempio seguente:
@Cacheable(value="accountCache")// 使用了一个缓存名叫 accountCache public Account getAccountByName(String userName) { // 方法内部实现不考虑缓存逻辑,直接实现业务 System.out.println("real query account."+userName); return getFromDB(userName); }
Annotazione @CacheEvict
@CacheEvict: annotazione per eliminare dati dalla cache, molto utile per rimuovere dati vecchi e inutili. È inoltre disponibile un parametro aggiuntivo (allEntries): impostando allEntries=true, è possibile eliminare in blocco tutte le voci.
| Parametri | Spiegazione | esempio |
| value | Nome della cache, definito nel file di configurazione spring ; è necessario specificarne almeno uno | @CacheEvict(value=”my cache”) |
| key | La key della cache può essere vuota; se specificata, deve essere scritta come espressione SpEL; se non viene specificata, per impostazione predefinita viene composta usando tutti i parametri del metodo | @CacheEvict(value=”testcache”,key=”#userName”) |
| condition | Condizione per la memorizzazione nella cache, può essere vuota ed è scritta in SpEL; restituisce true oppure false, e la memorizzazione avviene solo se è true | @CacheEvict(value=”testcache”,condition=”#userName.length()>2”) |
| allEntries | Indica se svuotare tutta la cache; il valore predefinito è false; se viene specificato true, tutta la cache verrà svuotata immediatamente dopo la chiamata al metodo | @CachEvict(value=”testcache”,allEntries=true) |
| beforeInvocation | Indica se svuotare la cache prima dell’esecuzione del metodo; il valore predefinito è false. Se impostato su true, la cache viene svuotata prima che il metodo venga eseguito; per impostazione predefinita, se il metodo genera un’eccezione durante l’esecuzione, la cache non viene svuotata | @CachEvict(value=”testcache”,beforeInvocation=true) |
@CacheEvict(value="accountCache",key="#account.getName()")// 清空accountCache 缓存 public void updateAccount(Account account) { updateDB(account); } @CacheEvict(value="accountCache",allEntries=true)// 清空accountCache 缓存 public void reload() { reloadAll() } @Cacheable(value="accountCache",condition="#userName.length() <=4")// 缓存名叫 accountCache public Account getAccountByName(String userName) { // 方法内部实现不考虑缓存逻辑,直接实现业务 return getFromDB(userName); }
Annotazione @CachePut
@CachePut:questa annotazione si può utilizzare quando occorre aggiornare la cache senza interferire con l'esecuzione del metodo. In altre parole, il metodo viene sempre eseguito e il risultato viene inserito nella cache;
| Parametri | Spiegazione | esempio |
| value | Nome della cache, definito nel file di configurazione spring ; è necessario specificarne almeno uno | @CachePut(value=”my cache”) |
| key | La key della cache può essere vuota; se specificata, deve essere scritta come espressione SpEL; se non viene specificata, per impostazione predefinita viene composta usando tutti i parametri del metodo | @CachePut(value=”testcache”,key=”#userName”) |
| condition | Condizione per la memorizzazione nella cache, può essere vuota ed è scritta in SpEL; restituisce true oppure false, e la memorizzazione avviene solo se è true | @CachePut(value=”testcache”,condition=”#userName.length()>2”) |
L’annotazione @CachePut garantisce l’esecuzione del metodo e registra anche il suo valore restituito nella cache, aggiornando così in modo sincronizzato la cache e il database.
@CachePut(value="accountCache",key="#account.getName()")// 更新accountCache 缓存 public Account updateAccount(Account account) { return updateDB(account); }
Annotazione @Caching
Quando si usa la cache, può essere necessario eseguire contemporaneamente aggiornamenti ed eliminazioni, utilizzando quindi più annotazioni insieme.E @Caching permette di
//添加user缓存的同时,移除userPage的缓存 @Caching( put =@CachePut(value = "user",key ="#userVo.id"), evict = @CacheEvict(value = "userPage",allEntries = true) )
@Caching(put = { @CachePut(value = "user", key = "#user.id"), @CachePut(value = "user", key = "#user.username"), @CachePut(value = "user", key = "#user.email") }) public User save(User user) {
@CacheConfig
Tutte le @Cacheable() contengono un attributo value=“xxx”; ovviamente, con molti metodi, scriverlo ogni volta diventa piuttosto faticoso. Sarebbe più comodo poterlo dichiarare una volta sola. Per questo esiste la configurazione @CacheConfig: @CacheConfig è un'annotazione a livello di classe che consente di condividere i nomi delle cache; se specifichi un nome diverso su un metodo, prevale comunque il nome indicato sul metodo.
@CacheConfig("books") public class BookRepositoryImpl implements BookRepository { @Cacheable public Book findBook(ISBN isbn) {...} }
Caching condizionale
Di seguito sono riportati alcuni esempi comuni di caching condizionale
//@Cacheable将在执行方法之前( #result还拿不到返回值)判断condition,如果返回true,则查缓存; @Cacheable(value = "user", key = "#id", condition = "#id lt 10") public User conditionFindById(final Long id) //@CachePut将在执行完方法后(#result就能拿到返回值了)判断condition,如果返回true,则放入缓存; @CachePut(value = "user", key = "#id", condition = "#result.username ne 'zhang'") public User conditionSave(final User user) //@CachePut将在执行完方法后(#result就能拿到返回值了)判断unless,如果返回false,则放入缓存;(即跟condition相反) @CachePut(value = "user", key = "#user.id", unless = "#result.username eq 'zhang'") public User conditionSave2(final User user) //@CacheEvict, beforeInvocation=false表示在方法执行之后调用(#result能拿到返回值了);且判断condition,如果返回true,则移除缓存; @CacheEvict(value = "user", key = "#user.id", beforeInvocation = false, condition = "#result.username ne 'zhang'") public User conditionDelete(final User user)
Annotazioni personalizzate per la cache
Per esempio, la combinazione con @Caching vista prima può rendere il codice piuttosto disordinato per via delle annotazioni sul metodo. In questo caso si può usare un'annotazione personalizzata per riunirle tutte in una sola, come segue:
@Caching(put = { @CachePut(value = "user", key = "#user.id"), @CachePut(value = "user", key = "#user.username"), @CachePut(value = "user", key = "#user.email") }) @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface UserSaveCache { }
In questo modo basta usare il seguente codice sul metodo, e il codice nel suo insieme risulta piuttosto pulito.
@UserSaveCache public User save(User user)
Estensione
Per esempio, quando si usa findByUsername, non bisognerebbe inserire soltanto username–>user, ma anche id—>user ed email—>user insieme;così, alla successiva ricerca per id, il risultato sarà trovato direttamente nella cache
@Caching( cacheable = { @Cacheable(value = "user", key = "#username") }, put = { @CachePut(value = "user", key = "#result.id", condition = "#result != null"), @CachePut(value = "user", key = "#result.email", condition = "#result != null") } ) public User findByUsername(final String username) { System.out.println("cache miss, invoke find by username, username:" + username); for (User user : users) { if (user.getUsername().equals(username)) { return user; } } return null; }
In realtà, per:id—>user;username—->user;email—>user;un approccio migliore potrebbe essere:id—>user;username—>id;email—>id;garantendo che user sia memorizzato una sola volta;per esempio:
@CachePut(value="cacheName", key="#user.username", cacheValue="#user.username") public void save(User user) @Cacheable(value="cacheName", key="#user.username", cacheValue="#caches[0].get(#caches[0].get(#username).get())") public User findByUsername(String username)
Dati di contesto SpEL
Spring Cache mette a disposizione alcuni dati di contesto SpEL; la tabella seguente è tratta direttamente dalla documentazione ufficiale di Spring:
| Nome | Posizione | Descrizione | Esempio |
| methodName | Oggetto root | Il nome del metodo attualmente invocato | root.methodName |
| metodo | Oggetto root | Metodo attualmente chiamato | root.method.name |
| target | Oggetto root | L'oggetto di destinazione attualmente invocato | root.target |
| targetClass | Oggetto root | Classe dell'oggetto di destinazione attualmente invocato | root.targetClass |
| args | Oggetto root | Elenco dei parametri del metodo attualmente invocato | root.args[0] |
| caches | Oggetto root | Elenco delle cache utilizzate dalla chiamata al metodo corrente(ad esempio @Cacheable(value={“cache1”, “cache2”})),in questo caso le cache sono due | root.caches[0].name |
| nome dell'argomento | Contesto di esecuzione | I parametri del metodo attualmente invocato, come findById(Long id): possiamo ottenere il parametro tramite #id | user.id |
| result | Contesto di esecuzione | Valore restituito dopo l’esecuzione del metodo (valido solo per le condizioni valutate dopo l’esecuzione del metodo, come ‘unless', o 'cache evict' con beforeInvocation=false) | result |
@CacheEvict(value = "user", key = "#user.id", condition = "#root.target.canCache() and #root.caches[0].get(#user.id).get().username ne #user.username", beforeInvocation = true) public void conditionUpdate(User user)
Riepilogo
Per dichiarare la cache, il supporto alla cache di Spring fornisce una serie di annotazioni Java:
· @Cacheable
o
Funzione: attiva la scrittura nella cache; se il dato non è presente nella cache, interroga il database, lo memorizza nella cache e restituisce il risultato; se è presente, restituisce direttamente il risultato
o Applicazione:Interrogare il database Metodo
· @CacheEvict
o
Funzione: attivare lo svuotamento della cache
o Applicazione:Eliminare o modificare il database Metodo
· @CachePut
o
Funzione: scrittura nella cache (non influisce sull'esecuzione del metodo).
o Applicazione:Aggiungere al database Metodo
· @Memorizzazione nella cache
o
Funzione: raggruppare più operazioni di cache da applicare a un metodo
o Applicazione:uso combinato delle annotazioni precedenti