本文基于《Spring實戰(zhàn)(第4版)》所寫昂利。
啟用對緩存的支持
Spring對緩存的支持有兩種方式:
- 注解驅動的緩存
- XML聲明的緩存
使用Spring的緩存抽象時诽里,最為通用的方式就是在方法上添加@Cacheable和@CacheEvict注解籽腕。
在往bean上添加緩存注解之前丑勤,必須要啟用Spring對注解驅動緩存的支持稳强。如果我們使用Java配置的話敷待,那么可以在其中的一個配置類上添加@EnableCaching间涵,這樣的話就能啟動注解驅動的緩存。下面的程序展現(xiàn)了如何實際使用@EnableCaching榜揖。
package spittr.config;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableCaching // 啟用緩存
public class CachingConfig {
@Bean
public CacheManager cacheManager(){ // 聲明緩存管理器
return new ConcurrentMapCacheManager();
}
}
如果以XML的方式配置應用的話勾哩,那么可以使用Spring cache命名空間中的<cache:annotation-driven>元素來啟動注解驅動的緩存。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd">
<cache:annotation-driven />
<bean id="cacheManager" class="org.springframework.cache.concurrent.ConcurrentMapCacheManager" />
</beans>
本質上举哟,@EnableCaching和<cache:annotation-driven />的工作方式是相同的思劳。它們都會創(chuàng)建一個切面(aspect)并觸發(fā)Spring緩存注解的切點(pointcut)。根據(jù)所使用的注解以及緩存的狀態(tài)妨猩,這個切面會從緩存中獲取數(shù)據(jù)潜叛,將數(shù)據(jù)添加到緩存之中或者從緩存中移除某個值。
上面的程序配置中,它們不僅僅啟用了注解驅動的緩存威兜,還聲明了一個緩存管理器(cache manager)的bean销斟。緩存管理器是Spring緩存抽象的核心,它能夠與多個流行的緩存實現(xiàn)進行集成椒舵。
本例中暖呕,聲明了ConcurrentMapManager眉踱,這個簡單的緩存管理器使用java.util.concurrent.ConcurrentHashMap作為緩存存儲。它的緩存存儲是基于內存的,所以它的生命周期是與應用關聯(lián)的诱告,對于生產級別的大型企業(yè)級應用程序臼疫,這可能并不是理想的選擇鳖谈。
配置緩存管理器
Spring 3.1內置了五個緩存管理器實現(xiàn)秩命,如下所示:
- SimpleCacheManager
- NoOpCacheManager
- ConcurrentMapCacheManager
- CompositeCacheManager
- EhCacheCacheManager
Spring 3.2引入了另外一個緩存管理器,這個管理器可以用在基于JCache(JSR-107)的緩存提供商之中侥加。除了核心的Spring框架捧存,Spring Data又提供了兩個緩存管理器:
- RedisCacheManager(來自于Spring Data Redis項目)
- GemfireCacheManager(來自于Spring Data GemFire項目)
具體選擇哪一個要取決于想要使用的底層緩存供應商。盡管所作出的選擇會影響到數(shù)據(jù)如何緩存担败,但是Spring聲明緩存的方式上并沒有什么差別昔穴。
我們必須選擇一個緩存管理器,然后要在Spring 應用上下文中提前,以bean的形式對其進行配置吗货。
使用Redis緩存
如果仔細想一下的話,緩存的條目不過是一個鍵值對(key-value pair)狈网,其中key描述了產生value的操作和參數(shù)宙搬。因此,很自然地就會想到拓哺,Redis作為key-value存儲勇垛。非常適合于存儲緩存。
Redis可以用來為Spring緩存抽象機制存儲緩存條目士鸥,Spring Data Redis提供了RedisCacheManager闲孤,這是CacheManager的一個實現(xiàn)。RedisCacheManager會與一個Redis服務器協(xié)作烤礁,并通過RedisTemplate將緩存條目存儲到Redis中讼积。
為了使用RediCacheManager,我們需要RedisConnectionFactory實現(xiàn)類(JedisConnnectionFactory)的bean。之前的篇章脚仔,已經看到了這些bean該如何配置勤众。在RedisConnectionFactory就緒之后,就可以配置RedisCacheManager了
package spittr.config;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
@Configuration
@EnableCaching // 啟用緩存
public class CachingConfig {
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory){
return RedisCacheManager.create(redisConnectionFactory);
}
@Bean
public JedisConnectionFactory jedisConnectionFactory() {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration("localhost", 6379);
redisStandaloneConfiguration.setPassword(RedisPassword.of("123456"));
redisStandaloneConfiguration.setDatabase(6);
return new JedisConnectionFactory(redisStandaloneConfiguration);
}
}
為方法添加注解以支持緩存
如前文所述鲤脏,Spring的緩存抽象在很大程度上圍繞切面構建的们颜。在Spring中啟用緩存時,會創(chuàng)建一個切面,它觸發(fā)一個或更多的Spring的緩存注解掌桩。下表列出了Spring所提供的緩存注解。
下表的所有注解都能運用在方法或類上姑食。當將其放在單個方法上時波岛,注解所描述的緩存行為只會運用到這個方法上。如果注解放在類級別的話音半,那么緩存行為就會應用到這個類的所有方法上则拷。
注解 | 描述 |
---|---|
@Cacheable | 表明Spring在調用方法之前,首先應該在緩存中查找方法的返回值曹鸠。如果這個值能夠找到煌茬,就會返回緩存的值。否則的話彻桃,這個方法就會被調用坛善,返回值會放到緩存之中。 |
@CachePut | 表明Spring應該將方法的返回值放到緩存中邻眷。在方法的調用前并不會檢查緩存眠屎,方法始終都會被調用 |
@CacheEvict | 表明Spring應該在緩存中清除一個或多個條目 |
@Caching | 這是一個分組的注解,能夠同時應用多個其他的緩存注解 |
填充緩存
@Cacheable和@CachePut注解都可以填充緩存肆饶,但是它們的工作方式略有差異改衩。
@Cacheable首先在緩存中查找條目,如果找到了匹配的條目驯镊,那么就不會對方法進行調用了葫督。如果沒有找到匹配的條目,方法會被調用并且返回值要放到緩存之中板惑。而@CachePut并不會在緩存中檢查匹配的值橄镜,目標放方法總是會被調用,并將返回值添加到緩存之中冯乘。
@Cacheable和@CachePut有一些屬性是共有的蛉鹿,見下表
屬性 | 類型 | 描述 |
---|---|---|
value | String[] | 要使用的緩存名稱 |
condition | String | SpEL表達式,如果得到的值是false的話往湿,不會將緩存應用到方法調用上 |
key | String | SpEL表達式妖异,用來計算自定義的緩存key |
unless | String | SpEL表達式,如果得到的值是true的話领追,返回值不會放到緩存之中 |
在最簡單的情況下他膳,在@Cacheable和@CachePut的這些屬性中,只需使用value屬性指定一個或多個緩存即可绒窑。例如棕孙,考慮SpittleRepository的findOne()方法。在初始保存之后,Spittle就不會再發(fā)生變化了蟀俊。如果有的Spittle比較熱門并且會被頻繁請求钦铺,反復地在數(shù)據(jù)庫中進行獲取是對時間和資源的浪費。通過在findOne()方法上添加@Cacheable注解肢预,如下面的程序所示矛洞,能夠確保將Spittle保存在緩存中,從而避免對數(shù)據(jù)庫的不必要訪問烫映。
@Cacheable("spittleCache") // 緩存這個方法的結果
public Spittle findOne(long id) {
List<Spittle> spittles = jdbc.query(
"select id, message, created_at, latitude, longitude" +
" from Spittle" +
" where id = ?",
new SpittleRowMapper(), id);
return spittles.size() > 0 ? spittles.get(0) : null;
}
當findOne() 被調用時沼本,緩存切面會攔截調用并在緩存中查找之前以名spittleCache存儲的返回值。緩存的key是緩存名加上傳遞到findOne()方法的id參數(shù)(spittleCache::6)锭沟。如果按照這個key能夠找到值的話抽兆,就會返回找到的值,方法不會在被調用族淮。如果沒有找到值的話辫红,那么就會調用這個方法,并將返回值放到緩存之中祝辣,為下一次調用findOne()方法做好準備厉熟。
在上面的程序清單中,@Cacheable注解被放到了JdbcSpittleRepository的findOne()方法實現(xiàn)上较幌。這樣能夠起作用揍瑟,但是緩存的作用只限于JdbcSpittleRepository這個實現(xiàn)類中,SpittleRepository的其他實現(xiàn)并沒有緩存功能乍炉,除非也其添加上@Cacheable注解绢片。因此,可以考慮將注解添加到SpittleRepository的方法聲明上岛琼,而不是放在實現(xiàn)類中:
@Cacheable("spittleCache")
Spittle findOne(long id);
當為接口方法添加注解后底循,@Cacheable注解會被SpittleRepository的所有實現(xiàn)繼承,這些實現(xiàn)類都會應用相同的緩存規(guī)則槐瑞。
將值放到緩存之中
@Cacheable會條件性地觸發(fā)對方法的調用熙涤,這取決于緩存中是不是已經有了所需要的值,對于所注解的方法困檩,@CachePut采用了一種更為直接的流程祠挫。帶有@CachePut注解的方法始終都會被調用,而且它的返回值也會放到緩存中悼沿。這提供一種很便利的機制等舔,能夠讓我們在請求之前預先加載緩存。
例如糟趾,當一個全新的Spittle通過SpittleRepository的save()方法保存之后慌植,很可能馬上就會請求這條記錄甚牲。所以,當save()方法調用后蝶柿,立即將Spittle塞到緩存之中是很有意義的丈钙,這樣當其他人通過findOne()對其進行查找時,它就已經準備就緒了交汤。為了實現(xiàn)這一點雏赦,可以在save()方法上添加@CachaPut注解,如下所示:
@CachePut("spittleCache")
Spittle save(Spittle spittle);
當save()方法被調用時蜻展,它首先會做所有必要的事情來保存Spittle,然后返回Spittle會被放到spittleCache緩存中邀摆。
但如果直接執(zhí)行的話纵顾,會報錯。因為默認的緩存要基于方法的參數(shù)來確定栋盹,這里唯一的參數(shù)就是Spittle施逾,所以它會用做緩存的key。但我們這里使用的是String的key例获,雖然也可以將Spittle作為key汉额,但顯然不是我們想要的key。
自定義緩存key
@Cacheable和@CachePut都有一個名為key屬性榨汤,這個屬性能夠替換默認的key蠕搜,它是通過一個SpEL表達式計算得到的。任意的SpEL表達式都是可行的收壕,但是更常見的場景是所定義的表達式與存儲在緩存中的值有關妓灌。據(jù)此計算得到key。
具體到我們這個場景蜜宪,我們需要將key設置為所保存Spittle的ID虫埂。以參數(shù)形式傳遞給save() 的Spittle還沒有保存,因此并沒有ID圃验。我們只能通過save()返回的Spittle得到id屬性掉伏。
幸好,在為緩存編寫SpEL表達式的時候澳窑,Spring暴露了一些很有用的元數(shù)據(jù)斧散。下表列出了SpEL中可用的緩存元數(shù)據(jù)。
表達式 | 描述 |
---|---|
#root.args | 傳遞給緩存方法的參數(shù)摊聋,形式為數(shù)組 |
#root.caches | 該方法執(zhí)行時所對應的緩存颅湘,形式為數(shù)組 |
#root.target | 目標對象 |
#root.targetClass | 目標對象的類,是#root.target.class的簡寫形式 |
#root.method | 緩存方法 |
#root.methodName | 緩存方法的名字栗精,是#root.method.name的簡寫形式 |
#result | 方法調用的返回值(不能用在@Cacheable注解上) |
#Argument | 任意的方法參數(shù)名(如#argName)或參數(shù)索引(如#a0或#p0) |
對于save() 方法來說闯参,我們需要的鍵是所返回Spittle對象的id屬性瞻鹏。表達式#result能夠得到返回的Spittle。借助這個對象鹿寨,我們可以通過將key屬性設置為#result.id來引用id屬性:
@CachePut( value = "spittleCache", key = "#result.id")
Spittle save(Spittle spittle);
按照這種方式配置@CachePut新博,緩存不會去干涉save() 方法的執(zhí)行,但是返回的Spittle將會保存在緩存中脚草,并且緩存的key與Spittle的id屬性相同赫悄。
條件化緩存
通過為方法添加Spring的緩存注解,Spring就會圍繞著這個方法創(chuàng)建一個緩存切面馏慨。但是埂淮,在有些場景下我們可能希望將緩存功能關閉。
@Cacheable和@CachePut提供了兩個屬性用以實現(xiàn)條件化緩存:unless和condition写隶,這兩個屬性都接受一個SpEL表達式倔撞。如果unless屬性的SpEL表達式計算結果為true,那么緩存方法返回的數(shù)據(jù)就不會放到緩存中慕趴。與之類似痪蝇,如果conditon屬性的SpEL表達式計算結果為false,那么對于這個方法緩存就會被禁用掉冕房。
表面上來看躏啰,unless和condition屬性做的是相同的事情。但是耙册,這里有一點細微的差別给僵。unless屬性只能阻止將對象放進緩存,但是這個方法調用的時候详拙,依然會去緩存中進行查找想际,如果找到了匹配的值,就會返回找到的值溪厘。與之不同胡本,如果condition的表達式計算結果為false,那么在這個方法調用的過程中畸悬,緩存是被禁用的侧甫。就是說,不會去緩存進行查找蹋宦,同時返回值也不會放進緩存中披粟。
作為樣例(盡管有些牽強),假設對于message屬性包含“NoCache”的Spittle對象冷冗,我們不想對其進行緩存守屉。為了阻止這樣的Spittle對象被緩存起來,可以這樣設置unless屬性:
@Cacheable(value = "spittleCache", unless = "#result.message.contains('NoCache')")
Spittle findOne(long id);
為unless設置的SpEL表達式會檢查返回的Spittle對象(在表達式中通過#result來識別)的message屬性蒿辙。如果它包含“NoCache”文本內容拇泛,那么這個表達式的計算值為true滨巴,這個Spittle對象不會放進緩存中。否則的話俺叭,表達式的計算結果為false恭取,無法滿足unless的條件,這個Spittle對象會被緩存熄守。
屬性unless能夠阻止將值寫入到緩存中蜈垮,但是有時候我們希望將緩存全部禁用,也就是說裕照,在一定的條件下攒发,我們既不希望將值添加到緩存中,也不希望從緩存中獲取數(shù)據(jù)晋南。
例如惠猿,對于ID值小于10的Spittle對象,我們不希望對其使用緩存搬俊。在這種場景下紊扬,這些Spittle是用來進行調試的測試條目蜒茄,對其進行緩存并沒有實際的價值唉擂。為了要對ID小于10的Spittle關閉緩存,可以在@Cacheable上使用condition屬性檀葛,如下所示:
@Cacheable(value = "spittleCache",
unless = "#result.message.contains('NoCache')",
condition="#id >= 10")
Spittle findOne(long id);
如果findOne()調用時玩祟,參數(shù)值小于10,那么將不會在緩存中進行查找屿聋,返回的Spittle也不會放進緩存中空扎,就像這個方法沒有添加@Cacheable注解一樣。
如樣例所示润讥,unless屬性的表達式能夠通過#result引用返回值转锈。這是很有用的,這么做之所以可行是因為unless屬性只有在緩存方法有返回值時才開始發(fā)揮作用楚殿。而condition肩負著在方法上禁用緩存的任務撮慨,因此它不能等到方法返回時在確定是否該關閉緩存。這意味著它的表達式必須要在進入方法時進行計算脆粥,所以我們不能通過#result引用發(fā)揮之砌溺。
移除緩存條目
@CacheEvict并不會往緩存中添加任何東西。相反变隔,如果帶有@CacheEvict注解的方法被調用的話规伐,那么會有一個或更多的條目會在緩存中移除。
當緩存值不再合法時匣缘,我們應該確保將其從緩存中移除猖闪,這樣的話鲜棠,后續(xù)的緩存中就不會返回舊的或者已經不存在的值,其中一個這樣的場景就是數(shù)據(jù)被刪除掉了萧朝。這樣的話岔留,SpittleRepository的remove() 方法就是使用@CacheEvict的絕佳選擇:
@CacheEvict("spittleCache")
void remove(long spittleId);
注意:與@Cacheable和@CachePut不同,@CacheEvict能夠應用在返回值為void的方法上检柬,而@Cacheable和@CachePut需要非void的返回值献联,它將會作為放在緩存中的條目。因為@CacheEvict只是將條目從緩存中移除何址,因此它可以放在任意的方法上里逆,甚至void方法。
從這里可以看到用爪,當remove() 調用時原押,會從緩存中刪除一個條目。被刪除條目的key與傳遞進來的spittleId參數(shù)的值相等偎血。
@CacheEvict有多個屬性诸衔,如下表,這些屬性會影響到該注解的行為颇玷,使其不同于默認的做法笨农。
可以看到,@CacheEvict的一些屬性與@Cacheable和@CachePut是相同的帖渠,另外還有幾個新的屬性谒亦。與@Cacheable和@CachePut不同,@CacheEvict并沒有提供unless屬性空郊。
屬性 | 類型 | 描述 |
---|---|---|
value | String[] | 要使用的緩存名稱 |
key | String | SpEL表達式份招,用來計算自定義的緩存key |
condition | String | SpEL表達式,如果得到的值是false的話狞甚,不會將緩存應用到方法調用上 |
allEntries | boolean | 如果為true的話锁摔,特定緩存的所有條目都會被移除掉 |
beforeInvocation | boolean | 如果為true的話,在方法調用之前移除條目哼审。如果為false(默認值)的話谐腰,在方法成功調用之后再移除條目 |
使用XML聲明緩存
如果需要在沒有源碼的bean上應用緩存功能,最好將緩存配置與緩存數(shù)據(jù)的代碼分隔開來棺蛛。Spring的cache命名空間提供了使用XML聲明緩存規(guī)則的方法怔蚌,可以作為面向注解緩存的替代方法。因為緩存是一種面向切面的行為旁赊,所以cache命名空間會與Spring的aop命名空間結合起來使用桦踊,用來聲明緩存所應用的切點在哪里。
要開始配置XML聲明的緩存终畅,首先需要創(chuàng)建Spring配置文件籍胯,這個文件中要包含cache和aop命名空間:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd">
</beans>
cache命名空間定義了在Spring XML配置文件中聲明緩存的配置元素竟闪。下表列出了cache命名空間所提供的所有元素。
元素 | 描述 |
---|---|
<cache:annotation-driven> | 啟動注解驅動的緩存杖狼。等同于Java配置中的@EnableCaching |
<cache:advice> | 定義緩存通知(advice)炼蛤。結合<aop:advisor>,將通知應用到切點上 |
<cache:caching> | 在緩存通知中蝶涩,定義一組特定的緩存規(guī)則 |
<cache:cacheable> | 指明某個方法要進行緩存理朋。等同于@Cacheable注解 |
<cache:cache-put> | 指明某個方法要填充緩存,但不會考慮緩存中是否有匹配的值绿聘。等同于@CachePut注解 |
<cache:cache-evict> | 指明某個方法要從緩存中移除一個或多個條目嗽上,等同于@CacheEvict注解 |
接下來的代碼清單展現(xiàn)了如何使用這些元素為SpittleRepository bean配置緩存,其作用等同于前面使用緩存注解的方法熄攘。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd">
<!--將緩存通知綁定到一個切點上-->
<aop:config>
<aop:advisor advice-ref="cacheAdvice"
pointcut="execution(* spittr.data.SpittleRepository.*(..))" />
</aop:config>
<cache:advice id="cacheAdvice">
<cache:caching>
<cache:cacheable cache="spittleCache"
method="findRecent" />
<cache:cacheable cache="spittleCache"
method="findOne" />
<cache:cacheable cache="spittleCache"
method="findBySpitterId" />
<cache:cache-put cache="spittleCache"
method="save"
key="#result.id"/>
<cache:cache-evict cache="spittleCache"
method="remove"/>
</cache:caching>
</cache:advice>
<bean id="cacheManager" class="org.springframework.cache.concurrent.ConcurrentMapCacheManager" />
</beans>
在上述程序中兽愤,我們首先看到的是<aop:advisor>,它引用ID為cacheAdvice的通知挪圾,該元素將這個通知與一個切點進行匹配浅萧,因此建立了一個完整的切面。在本例中哲思,這個切面的切點會在執(zhí)行SpittleRepository的任意方法時觸發(fā)洼畅。如果這樣的方法被Spring應用上下文中的任意某個bean所調用,那么就會調用切面的通知也殖。
在這里土思,通知利用<cache:advice>元素進行了聲明务热。在<cache:advice>元素中忆嗜,可以包含任意數(shù)量的<cache:caching>元素,這些元素用來完整地定義應用的緩存規(guī)則崎岂。在本例中捆毫,只包含了一個<cache:caching>元素。這個元素又包含了三個<cache:cacheable>元素和一個<cache:cache-put>元素冲甘。
每個<cache:cacheable>元素都聲明了切點中的某一個方法是支持緩存的绩卤。這是與@Cacheable注解同等作用的XML元素。具體來講江醇,findRecent()濒憋、findOne()和findBySpitterId()都聲明為支持緩存,它們的返回值將會保存在名為spittleCache的緩存之中陶夜。
<cache:cache-put>和<cache:cache-evict>元素也都與@CachePut和@CacheEvict注解等效功能凛驮。
需要注意的是,<cache:advice>元素有一個cache-manager元素条辟,用來指定作為緩存管理器的bean黔夭。它的默認值是cacheManager宏胯,這與xml配置中底部的<bean>聲明恰好是一致的,所以沒有必要再顯式地進行設置本姥。但是肩袍,如果緩存管理器的ID與之不同的話(使用多個緩存管理器的時候,可能會遇到這樣的場景)婚惫,那么可以通過設置cache-manager屬性指定要使用哪個緩存管理器氛赐。
另外,還要留意的是先舷,<cache:cacheable>鹰祸、<cache:cache-put>和<cache:cache-evict>元素都引用了同一個名為spittleCache的緩存。為了消除這種重復密浑,我們可以在<cache:caching>元素上指明緩存的名字:
<cache:advice id="cacheAdvice">
<cache:caching cache="spittleCache">
<cache:cacheable method="findRecent" />
<cache:cacheable method="findOne" />
<cache:cacheable method="findBySpitterId" />
<cache:cache-put method="save"
key="#result.id"/>
<cache:cache-evict method="remove"/>
</cache:caching>
</cache:advice>
<cache:caching> 有幾個可以供<cache:cacheable>蛙婴、<cache:cache-put>和<cache:cache-evict>共享的屬性。包括:
cache:指明要存儲和獲取值的緩存尔破;
condition: SpEL表達式街图,如果計算得到的值為false,將會為這個方法禁用緩存懒构;
key:SpEL表達式餐济,用來得到緩存的key(默認為方法的參數(shù));
method:要緩存的方法名胆剧。
除此之外絮姆,<cache:cacheable>和<cache:cache-put>還有一個unless屬性,可以為這個可選的屬性指定一個SpEL表達式秩霍,如果這個表達式的計算結果為true篙悯,那么將會阻止返回值放到緩存之中。
<cache:cache-evict>元素還有幾個特有的屬性:
- all-entries: 如果是true的話铃绒,緩存中所有的條目都會被移除掉鸽照。如果是false的話,只有匹配key的條目才會被移除掉颠悬。
- before-invocation: 如果是true的話矮燎,緩存條目將會在方法調用之前被移除掉。如果是false的話赔癌,方法調用之后才會移除緩存诞外。
all-entries和before-invocation的默認值都是false。這意味著在使用<cache:cache-evict>元素且不配置這兩個屬性時灾票,會在方法調用完成后只刪除一個緩存條目峡谊。要刪除的條目會通過默認的key(基于方法的參數(shù))進行識別,當然也可以通過為名為key的屬性設置一個SpEL表達式指定要刪除的key。