Spring實戰(zhàn)(十三)-緩存數(shù)據(jù)

本文基于《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。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末靖苇,一起剝皮案震驚了整個濱河市席噩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌贤壁,老刑警劉巖悼枢,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異脾拆,居然都是意外死亡馒索,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門名船,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绰上,“玉大人,你說我怎么就攤上這事渠驼◎诳椋” “怎么了?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵迷扇,是天一觀的道長百揭。 經常有香客問我,道長蜓席,這世上最難降的妖魔是什么器一? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮厨内,結果婚禮上祈秕,老公的妹妹穿的比我還像新娘。我一直安慰自己雏胃,他們只是感情好请毛,可當我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著丑掺,像睡著了一般获印。 火紅的嫁衣襯著肌膚如雪述雾。 梳的紋絲不亂的頭發(fā)上街州,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天,我揣著相機與錄音玻孟,去河邊找鬼唆缴。 笑死,一個胖子當著我的面吹牛黍翎,可吹牛的內容都是我干的面徽。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼趟紊!你這毒婦竟也來了氮双?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤霎匈,失蹤者是張志新(化名)和其女友劉穎戴差,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體铛嘱,經...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡暖释,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了墨吓。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片球匕。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖帖烘,靈堂內的尸體忽然破棺而出亮曹,到底是詐尸還是另有隱情,我是刑警寧澤秘症,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布乾忱,位于F島的核電站,受9級特大地震影響历极,放射性物質發(fā)生泄漏窄瘟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一趟卸、第九天 我趴在偏房一處隱蔽的房頂上張望蹄葱。 院中可真熱鬧,春花似錦锄列、人聲如沸图云。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽竣况。三九已至,卻和暖如春筒严,著一層夾襖步出監(jiān)牢的瞬間丹泉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工鸭蛙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留摹恨,地道東北人。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓娶视,卻偏偏與公主長得像晒哄,于是被迫代替她去往敵國和親睁宰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,527評論 2 349

推薦閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理寝凌,服務發(fā)現(xiàn)柒傻,斷路器,智...
    卡卡羅2017閱讀 134,633評論 18 139
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,773評論 6 342
  • http://liuxing.info/2017/06/30/Spring%20AMQP%E4%B8%AD%E6%...
    sherlock_6981閱讀 15,892評論 2 11
  • Spring Boot緩存 《Spring Boot 實戰(zhàn)開發(fā)》—— 基于 Gradle + Kotlin的企業(yè)級...
    光劍書架上的書閱讀 5,824評論 2 18
  • spring官方文檔:http://docs.spring.io/spring/docs/current/spri...
    牛馬風情閱讀 1,650評論 0 3