【轉(zhuǎn)】Spring Boot Cache使用與整合

地址:https://www.cnblogs.com/yueshutong/p/9381540.html

一:Spring緩存抽象

Spring從3.1開始定義了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口來統(tǒng)一不同的緩存技術(shù)遇革;并支持使用JCache(JSR-107)注解簡化我們開發(fā)琢唾;

Cache接口為緩存的組件規(guī)范定義憔四,包含緩存的各種操作集合;

Cache接口下Spring提供了各種xxxCache的實現(xiàn)掂为;如RedisCache甩十,EhCacheCache ,ConcurrentMapCache等闹炉;

每次調(diào)用需要緩存功能的方法時懈糯,Spring會檢查檢查指定參數(shù)的指定的目標方法是否已經(jīng)被調(diào)用過;如果有就直接從緩存中獲取方法調(diào)用后的結(jié)果颁督,如果沒有就調(diào)用方法并緩存結(jié)果后返回給用戶践啄。下次調(diào)用直接從緩存中獲取。

使用Spring緩存抽象時我們需要關(guān)注以下兩點沉御;

1屿讽、確定方法需要被緩存以及他們的緩存策略

2、從緩存中讀取之前緩存存儲的數(shù)據(jù)

二:幾個重要概念&緩存注解

名稱解釋

Cache緩存接口吠裆,定義緩存操作伐谈。實現(xiàn)有:RedisCache烂完、EhCacheCache、ConcurrentMapCache等

CacheManager緩存管理器衩婚,管理各種緩存(cache)組件

@Cacheable主要針對方法配置窜护,能夠根據(jù)方法的請求參數(shù)對其進行緩存

@CacheEvict清空緩存

@CachePut保證方法被調(diào)用效斑,又希望結(jié)果被緩存非春。

與@Cacheable區(qū)別在于是否每次都調(diào)用方法,常用于更新

@EnableCaching開啟基于注解的緩存

keyGenerator緩存數(shù)據(jù)時key生成策略

serialize緩存數(shù)據(jù)時value序列化策略

@CacheConfig統(tǒng)一配置本類的緩存注解的屬性

@Cacheable/@CachePut/@CacheEvict 主要的參數(shù)

名稱解釋

value緩存的名稱缓屠,在 spring 配置文件中定義奇昙,必須指定至少一個

例如:

@Cacheable(value=”mycache”) 或者

@Cacheable(value={”cache1”,”cache2”}

key緩存的 key,可以為空敌完,如果指定要按照 SpEL 表達式編寫储耐,

如果不指定,則缺省按照方法的所有參數(shù)進行組合

例如:

@Cacheable(value=”testcache”,key=”#id”)

condition緩存的條件滨溉,可以為空什湘,使用 SpEL 編寫,返回 true 或者 false晦攒,

只有為 true 才進行緩存/清除緩存

例如:@Cacheable(value=”testcache”,condition=”#userName.length()>2”)

unless否定緩存闽撤。當條件結(jié)果為TRUE時,就不會緩存脯颜。

@Cacheable(value=”testcache”,unless=”#userName.length()>2”)

allEntries

(@CacheEvict )

是否清空所有緩存內(nèi)容哟旗,缺省為 false,如果指定為 true栋操,

則方法調(diào)用后將立即清空所有緩存

例如:

@CachEvict(value=”testcache”,allEntries=true)

beforeInvocation

(@CacheEvict)

是否在方法執(zhí)行前就清空闸餐,缺省為 false,如果指定為 true矾芙,

則在方法還沒有執(zhí)行的時候就清空緩存舍沙,缺省情況下,如果方法

執(zhí)行拋出異常剔宪,則不會清空緩存

例如:

@CachEvict(value=”testcache”场勤,beforeInvocation=true)

三:SpEL上下文數(shù)據(jù)

Spring Cache提供了一些供我們使用的SpEL上下文數(shù)據(jù),下表直接摘自Spring官方文檔:

名稱位置描述示例

methodNameroot對象當前被調(diào)用的方法名#root.methodname

methodroot對象當前被調(diào)用的方法#root.method.name

targetroot對象當前被調(diào)用的目標對象實例#root.target

targetClassroot對象當前被調(diào)用的目標對象的類#root.targetClass

argsroot對象當前被調(diào)用的方法的參數(shù)列表#root.args[0]

cachesroot對象當前方法調(diào)用使用的緩存列表#root.caches[0].name

Argument Name執(zhí)行上下文當前被調(diào)用的方法的參數(shù)歼跟,如findArtisan(Artisan artisan),可以通過#artsian.id獲得參數(shù)#artsian.id

result執(zhí)行上下文方法執(zhí)行后的返回值(僅當方法執(zhí)行后的判斷有效和媳,如 unless cacheEvict的beforeInvocation=false)#result

注意:

1.當我們要使用root對象的屬性作為key時我們也可以將“#root”省略,因為Spring默認使用的就是root對象的屬性哈街。 如

@Cacheable(key = "targetClass + methodName +#p0")

2.使用方法參數(shù)時我們可以直接使用“#參數(shù)名”或者“#p參數(shù)index”留瞳。 如:

@Cacheable(value="users", key="#id")

@Cacheable(value="users", key="#p0")

SpEL提供了多種運算符

類型運算符

關(guān)系<,>骚秦,<=她倘,>=璧微,==,!=硬梁,lt前硫,gt,le荧止,ge屹电,eq,ne

算術(shù)+跃巡,- 危号,* ,/素邪,%外莲,^

邏輯&&,||兔朦,!偷线,and,or沽甥,not声邦,between,instanceof

條件?: (ternary)安接,?: (elvis)

正則表達式matches

其他類型?.翔忽,?[…],![…]盏檐,^[…]歇式,$[…]

以上的知識點適合你遺忘的時候來查閱,下面正式進入學習胡野!

四:開始使用

環(huán)境:Spring boot 2.0.3

IDE:IDEA

1.開始使用前需要導入依賴

<dependency>

? ? <groupId>org.springframework.boot</groupId>

? ? <artifactId>spring-boot-starter-cache</artifactId>

</dependency>

2.然后在啟動類注解@EnableCaching開啟緩存

@SpringBootApplication

@EnableCaching//開啟緩存

publicclass DemoApplication{

public static void main(String[] args){? ? ? ??

SpringApplication.run(DemoApplication.class, args);? ??

}

}

3.緩存@Cacheable

@Cacheable注解會先查詢是否已經(jīng)有緩存材失,有會使用緩存,沒有則會執(zhí)行方法并緩存硫豆。

@Cacheable(value="emp",key ="targetClass + methodName +#p0")

public List<NewJob> queryAll(User uid){

return newJobDao.findAllByUid(uid);? ??

}

此處的value是必需的龙巨,它指定了你的緩存存放在哪塊命名空間。

此處的key是使用的spEL表達式熊响,參考上章旨别。這里有一個小坑,如果你把methodName換成method運行會報錯汗茄,觀察它們的返回類型秸弛,原因在于methodName是String而methoh是Method。

此處的User實體類一定要實現(xiàn)序列化public class User implements Serializable,否則會報java.io.NotSerializableException異常递览。

到這里叼屠,你已經(jīng)可以運行程序檢驗緩存功能是否實現(xiàn)。

深入源碼绞铃,查看它的其它屬性

我們打開@Cacheable注解的源碼镜雨,可以看到該注解提供的其他屬性,如:

String[]cacheNames()default{};//和value注解差不多儿捧,二選一

StringkeyGenerator()default"";//key的生成器荚坞。key/keyGenerator二選一使用

StringcacheManager()default"";//指定緩存管理器

StringcacheResolver()default"";//或者指定獲取解析器

Stringcondition()default"";//條件符合則緩存

Stringunless()default"";//條件符合則不緩存

booleansync()default false;//是否使用異步模式

4.配置@CacheConfig

當我們需要緩存的地方越來越多,你可以使用@CacheConfig(cacheNames = {"myCache"})注解來統(tǒng)一指定value的值纯命,這時可省略value西剥,如果你在你的方法依舊寫上了value痹栖,那么依然以方法的value值為準亿汞。

使用方法如下:

@CacheConfig(cacheNames = {"myCache"})publicclass BotRelationServiceImpl implements BotRelationService {

@Override

@Cacheable(key ="targetClass + methodName +#p0")//此處沒寫

valuepublic List<BotRelation> findAllLimit(int num){

returnbotRelationRepository.findAllLimit(num);? ??

}? ??

.....}

查看它的其它屬性

StringkeyGenerator()default"";//key的生成器。key/keyGenerator二選一使用

StringcacheManager()default"";//指定緩存管理器

StringcacheResolver()default"";//或者指定獲取解析器

5.更新@CachePut

@CachePut注解的作用 主要針對方法配置揪阿,能夠根據(jù)方法的請求參數(shù)對其結(jié)果進行緩存疗我,和?@Cacheable?不同的是,它每次都會觸發(fā)真實方法的調(diào)用 南捂。簡單來說就是用戶更新緩存數(shù)據(jù)吴裤。但需要注意的是該注解的value?和?key?必須與要更新的緩存相同,也就是與@Cacheable?相同溺健。示例:

@CachePut(value="emp", key ="targetClass + #p0")

public NewJob updata(NewJob job){? ? ? ??

NewJob newJob = newJobDao.findAllById(job.getId());? ? ? ??

newJob.updata(job);returnjob;? ?

?}? ??

@Cacheable(value="emp", key ="targetClass +#p0")//清空緩存

public NewJob save(NewJob job){? ? ? ??

newJobDao.save(job);returnjob;? ??

}

查看它的其它屬性

String[]cacheNames()default{};//與value二選一

StringkeyGenerator()default"";//key的生成器麦牺。key/keyGenerator二選一使用

StringcacheManager()default"";//指定緩存管理器

StringcacheResolver()default"";//或者指定獲取解析器

Stringcondition()default"";//條件符合則緩存

Stringunless()default"";//條件符合則不緩存

6.清除@CacheEvict

@CachEvict?的作用 主要針對方法配置,能夠根據(jù)一定的條件對緩存進行清空 鞭缭。

屬性解釋示例

allEntries是否清空所有緩存內(nèi)容剖膳,缺省為 false,如果指定為 true岭辣,則方法調(diào)用后將立即清空所有緩存@CachEvict(value=”testcache”,allEntries=true)

beforeInvocation是否在方法執(zhí)行前就清空吱晒,缺省為 false,如果指定為 true沦童,則在方法還沒有執(zhí)行的時候就清空緩存仑濒,缺省情況下,如果方法執(zhí)行拋出異常偷遗,則不會清空緩存@CachEvict(value=”testcache”墩瞳,beforeInvocation=true)

示例:

@Cacheable(value="emp",key ="#p0.id")

public NewJob save(NewJob job){? ? ? ?

?newJobDao.save(job);returnjob;? ??

}//清除一條緩存,key為要清空的數(shù)據(jù)@CacheEvict(value="emp",key="#id")

public void delect(int id){? ? ? ??

newJobDao.deleteAllById(id);? ??

}//方法調(diào)用后清空所有緩存

@CacheEvict(value="accountCache",allEntries=true)

public void delectAll(){? ? ? ??

newJobDao.deleteAll();? ??

}//方法調(diào)用前清空所有緩存

@CacheEvict(value="accountCache",beforeInvocation=true)

public void delectAll(){? ? ? ??

newJobDao.deleteAll();? ??

}

其他屬性

String[]cacheNames()default{};//與value二選一

StringkeyGenerator()default"";//key的生成器氏豌。key/keyGenerator二選一使用

StringcacheManager()default"";//指定緩存管理器

StringcacheResolver()default"";//或者指定獲取解析器

Stringcondition()default"";//條件符合則清空

7.組合@Caching

有時候我們可能組合多個Cache注解使用喉酌,此時就需要@Caching組合多個注解標簽了。

@Caching(cacheable = {? ? ? ? ? ?

@Cacheable(value ="emp",key ="#p0"),...

},? ?

?put = {? ? ? ? ? ??

@CachePut(value ="emp",key ="#p0"),...

},

evict = {? ? ? ? ? ??

@CacheEvict(value ="emp",key ="#p0"),? ? ? ? ? ? ....? ??

})? ??

public User save(User user) {? ? ? ? ....? ? }

下面講到的整合第三方緩存組件都是基于上面的已經(jīng)完成的步驟,所以一個應(yīng)用要先做好你的緩存邏輯瞭吃,再來整合其他cache組件碌嘀。

五:整合EHCACHE

Ehcache是一種廣泛使用的開源Java分布式緩存。主要面向通用緩存,Java EE和輕量級容器歪架。它具有內(nèi)存和磁盤存儲股冗,緩存加載器,緩存擴展,緩存異常處理程序,一個gzip緩存servlet過濾器,支持REST和SOAP api等特點。

1.導入依賴

整合ehcache必須要導入它的依賴和蚪。

<dependency>

? ? <groupId>net.sf.ehcache</groupId>

? ? <artifactId>ehcache</artifactId>

</dependency>

<dependency>

? ? <groupId>org.springframework.boot</groupId>

? ? <artifactId>spring-boot-starter-cache</artifactId>

</dependency>

2.yml配置

需要說明的是config: classpath:/ehcache.xml可以不用寫止状,因為默認就是這個路徑。但ehcache.xml必須有攒霹。

spring:cache:type: ehcacheehcache:config:classpath:/ehcache.xml

3.ehcache.xml

在resources目錄下新建ehcache.xml怯疤,注釋啥的應(yīng)該可以說相當詳細了

<ehcache>

<!--

? ? ? ? 磁盤存儲:將緩存中暫時不使用的對象,轉(zhuǎn)移到硬盤,類似于Windows系統(tǒng)的虛擬內(nèi)存

? ? ? ? path:指定在硬盤上存儲對象的路徑

? ? ? ? path可以配置的目錄有:

? ? ? ? ? ? user.home(用戶的家目錄)

? ? ? ? ? ? user.dir(用戶當前的工作目錄)

? ? ? ? ? ? java.io.tmpdir(默認的臨時目錄)

? ? ? ? ? ? ehcache.disk.store.dir(ehcache的配置目錄)

? ? ? ? ? ? 絕對路徑(如:d:\\ehcache)

? ? ? ? 查看路徑方法:String tmpDir = System.getProperty("java.io.tmpdir");

? ? -->

<diskStore path="java.io.tmpdir" />

<!--

? ? ? ? defaultCache:默認的緩存配置信息,如果不加特殊說明,則所有對象按照此配置項處理

? ? ? ? maxElementsInMemory:設(shè)置了緩存的上限,最多存儲多少個記錄對象

? ? ? ? eternal:代表對象是否永不過期 (指定true則下面兩項配置需為0無限期)

? ? ? ? timeToIdleSeconds:最大的發(fā)呆時間 /秒

? ? ? ? timeToLiveSeconds:最大的存活時間 /秒

? ? ? ? overflowToDisk:是否允許對象被寫入到磁盤

? ? ? ? 說明:下列配置自緩存建立起600秒(10分鐘)有效 。

? ? ? ? 在有效的600秒(10分鐘)內(nèi)催束,如果連續(xù)120秒(2分鐘)未訪問緩存集峦,則緩存失效。

? ? ? ? 就算有訪問抠刺,也只會存活600秒塔淤。

? ? -->

<defaultCache maxElementsInMemory="10000" eternal="false"? ? ? ? ? ? ? ? ? timeToIdleSeconds="600" timeToLiveSeconds="600" overflowToDisk="true" />

<cache name="myCache" maxElementsInMemory="10000" eternal="false"? ? ? ? ? ? ? ? ? timeToIdleSeconds="120" timeToLiveSeconds="600" overflowToDisk="true" /></ehcache>

4.使用緩存

@CacheConfig(cacheNames = {“myCache”})設(shè)置ehcache的名稱,這個名稱必須在ehcache.xml已配置 速妖。

@CacheConfig(cacheNames = {"myCache"})

publicclass BotRelationServiceImpl implements BotRelationService {

@Cacheable(key ="targetClass + methodName +#p0")

public List<BotRelation> findAllLimit(int num)

{

returnbotRelationRepository.findAllLimit(num);? ??

}

}

整合完畢高蜂!

別忘了在啟動類開啟緩存!

六:整合Redis

Redis 優(yōu)勢

性能極高 – Redis能讀的速度是110000次/s,寫的速度是81000次/s 罕容。

豐富的數(shù)據(jù)類型 – Redis支持二進制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 數(shù)據(jù)類型操作备恤。

原子 – Redis的所有操作都是原子性的,意思就是要么成功執(zhí)行要么失敗完全不執(zhí)行锦秒。單個操作是原子性的露泊。多個操作也支持事務(wù),即原子性脂崔,通過MULTI和EXEC指令包起來滤淳。

豐富的特性 – Redis還支持 publish/subscribe, 通知, key 過期等等特性

1.啟動Redis

下載地址:https://github.com/MicrosoftArchive/redis/releases?

2.導入依賴

就只需要這一個依賴!不需要spring-boot-starter-cache

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

當你導入這一個依賴時砌左,SpringBoot的CacheManager就會使用RedisCache脖咐。

如果你的Redis使用默認配置,這時候已經(jīng)可以啟動程序了汇歹。

3.配置Redis

# Redis數(shù)據(jù)庫索引(默認為0)

spring.redis.database=1

# Redis服務(wù)器地址

spring.redis.host=127.0.0.1

# Redis服務(wù)器連接端口

spring.redis.port=6379

# Redis服務(wù)器連接密碼(默認為空)

spring.redis.password=

# 連接池最大連接數(shù)(使用負值表示沒有限制)

spring.redis.pool.max-active=1000

# 連接池最大阻塞等待時間(使用負值表示沒有限制)

spring.redis.pool.max-wait=-1

# 連接池中的最大空閑連接

spring.redis.pool.max-idle=10

# 連接池中的最小空閑連接

spring.redis.pool.min-idle=2

# 連接超時時間(毫秒)

spring.redis.timeout=0

4.模板編程

除了使用注解屁擅,我們還可以使用Redis模板。?

Spring boot集成 Redis 客戶端jedis产弹。封裝Redis 連接池派歌,以及操作模板弯囊。

@AutowiredprivateStringRedisTemplate stringRedisTemplate;//操作key-value都是字符串@AutowiredprivateRedisTemplate redisTemplate;//操作key-value都是對象/**

? ? *? Redis常見的五大數(shù)據(jù)類型:

? ? *? stringRedisTemplate.opsForValue();[String(字符串)]

? ? *? stringRedisTemplate.opsForList();[List(列表)]

? ? *? stringRedisTemplate.opsForSet();[Set(集合)]

? ? *? stringRedisTemplate.opsForHash();[Hash(散列)]

? ? *? stringRedisTemplate.opsForZSet();[ZSet(有序集合)]

? ? */public void test(){? ? ? ? stringRedisTemplate.opsForValue().append("msg","hello");? ? }

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市胶果,隨后出現(xiàn)的幾起案子匾嘱,更是在濱河造成了極大的恐慌,老刑警劉巖早抠,帶你破解...
    沈念sama閱讀 222,946評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件霎烙,死亡現(xiàn)場離奇詭異,居然都是意外死亡蕊连,警方通過查閱死者的電腦和手機悬垃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,336評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來甘苍,“玉大人尝蠕,你說我怎么就攤上這事≡赝ィ” “怎么了看彼?”我有些...
    開封第一講書人閱讀 169,716評論 0 364
  • 文/不壞的土叔 我叫張陵,是天一觀的道長昧捷。 經(jīng)常有香客問我闲昭,道長罐寨,這世上最難降的妖魔是什么靡挥? 我笑而不...
    開封第一講書人閱讀 60,222評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮鸯绿,結(jié)果婚禮上跋破,老公的妹妹穿的比我還像新娘。我一直安慰自己瓶蝴,他們只是感情好毒返,可當我...
    茶點故事閱讀 69,223評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著舷手,像睡著了一般拧簸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上男窟,一...
    開封第一講書人閱讀 52,807評論 1 314
  • 那天盆赤,我揣著相機與錄音,去河邊找鬼歉眷。 笑死牺六,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的汗捡。 我是一名探鬼主播淑际,決...
    沈念sama閱讀 41,235評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了春缕?” 一聲冷哼從身側(cè)響起盗胀,我...
    開封第一講書人閱讀 40,189評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎锄贼,沒想到半個月后读整,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,712評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡咱娶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,775評論 3 343
  • 正文 我和宋清朗相戀三年米间,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片膘侮。...
    茶點故事閱讀 40,926評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡屈糊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出琼了,到底是詐尸還是另有隱情逻锐,我是刑警寧澤,帶...
    沈念sama閱讀 36,580評論 5 351
  • 正文 年R本政府宣布雕薪,位于F島的核電站昧诱,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏所袁。R本人自食惡果不足惜盏档,卻給世界環(huán)境...
    茶點故事閱讀 42,259評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望燥爷。 院中可真熱鬧蜈亩,春花似錦、人聲如沸前翎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,750評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽港华。三九已至道川,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間立宜,已是汗流浹背冒萄。 一陣腳步聲響...
    開封第一講書人閱讀 33,867評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留赘理,地道東北人宦言。 一個月前我還...
    沈念sama閱讀 49,368評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像商模,于是被迫代替她去往敵國和親奠旺。 傳聞我的和親對象是個殘疾皇子蜘澜,可洞房花燭夜當晚...
    茶點故事閱讀 45,930評論 2 361

推薦閱讀更多精彩內(nèi)容