一、序言
Spring Cache是Spring體系下標(biāo)準(zhǔn)化緩存框架。Spring Cache有如下優(yōu)勢(shì):
- 緩存品種多
支持緩存品種多,常見(jiàn)緩存 Redis 、 EhCache 、 Caffeine 均支持。它們之間既能獨(dú)立使用,也能組合使用。
- 平滑遷移
Spring內(nèi)部支持的緩存,可實(shí)現(xiàn)無(wú)縫平滑遷移,無(wú)需修改業(yè)務(wù)邏輯。注解緩存的實(shí)現(xiàn)依賴于動(dòng)態(tài)代理。
大多數(shù)情況下使用的是注解版、少數(shù)情況下也能使用編程版。注解版與業(yè)務(wù)代碼高度解藕,因其依托動(dòng)態(tài)代理技術(shù)實(shí)現(xiàn),使用場(chǎng)景上有一定的限制。編程版嵌入業(yè)務(wù)代碼,代碼順序執(zhí)行,無(wú)前置使用條件。
二、基本概念
(一)核心概念
一個(gè)應(yīng)用可以有多個(gè)緩存管理器,每個(gè)緩存管理器可以有多個(gè)緩存,每個(gè)緩存可以存儲(chǔ)多條記錄。
1、緩存管理器
緩存的存儲(chǔ)介質(zhì)不同、緩存連接不同的數(shù)據(jù)庫(kù)、緩存值序列化等由緩存管理器配置。緩存管理器有主次之分,默認(rèn)情況下使用主(首要)緩存管理器。
當(dāng)服務(wù)內(nèi)只有一個(gè)CacheManager時(shí),默認(rèn)使用此緩存管理器;當(dāng)超過(guò)一個(gè)緩存管理器時(shí),需要使用 Primary 注解指定默認(rèn)緩存管理器。
2、緩存
Cache是一組配置相同緩存的集合,可以理解為命名空間,Spring Cache體系下的緩存生命時(shí)間是以Cache為單位的,不支持以Key為單位設(shè)置生存時(shí)間。不同的業(yè)務(wù)對(duì)應(yīng)不同的緩存配置,應(yīng)在緩存處予以區(qū)分。
CacheName應(yīng)具有顯著的業(yè)務(wù)區(qū)分度以及過(guò)期時(shí)間區(qū)分度,并且以全局常量的方式提供,采取集中化管理的方式,禁止采用魔術(shù)變量的方式指定CacheName。
(二)補(bǔ)充內(nèi)容
一般來(lái)說(shuō)緩存的Key與Value均是String類(lèi)型,特別是Value通常序列化成JSON串。
三、注解版
用于基于注解的方式來(lái)管理緩存數(shù)據(jù)。注解緩存有如下優(yōu)勢(shì):
- 高度解藕
使用注解來(lái)實(shí)現(xiàn)緩存,與業(yè)務(wù)高度解藕。
- 靈活管理
通過(guò)全局配置,不修改緩存邏輯,可實(shí)現(xiàn)如下效果:
開(kāi)發(fā)環(huán)境下,可禁用緩存,將流量打入數(shù)據(jù)庫(kù),盡早的暴露可能存在的性能瓶頸;測(cè)試環(huán)境開(kāi)啟緩存,進(jìn)行壓力測(cè)試等。
(一)動(dòng)態(tài)代理
Spring Cache緩存注解版的原理以及緩存配置失敗的典型案例。
1、CGLib動(dòng)態(tài)代理
緩存的實(shí)現(xiàn)底層技術(shù)支持是CGLib動(dòng)態(tài)代理,在目標(biāo)方法調(diào)用前、后分別追加相應(yīng)的緩存操作,以達(dá)到添加緩存、更新緩存、刪除緩存的操作。
如果注解緩存配置未生效,檢查目標(biāo)調(diào)用方法是否被動(dòng)態(tài)代理。
2、配置失效
配置失效是指盡管配置了緩存注解,但緩存仍然未生效。
- final類(lèi)與final方法
final類(lèi)與final方法不滿足CGLib動(dòng)態(tài)代理的條件,因此緩存配置會(huì)失效。
- 內(nèi)部調(diào)用
使用依賴注入的方式調(diào)用配置緩存的方法生效,方法間內(nèi)部調(diào)用不生效。
- 非public方法
非public方法配置緩存不生效。
(二)常用注解
1、配置注解
(1)EnableCaching
標(biāo)注于SpringBoot應(yīng)用啟動(dòng)類(lèi)上,添加此注解表示開(kāi)啟Spring Cache緩存;移除表示關(guān)閉緩存。如果在全局配置文件中添加如下配置,即使在啟動(dòng)類(lèi)上標(biāo)注EnableCaching注解,Spring Cache緩存然后是關(guān)閉狀態(tài)。
<pre class="hljs less" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 0.75em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">spring:
cache:
type: none</pre>
如果應(yīng)用中自定義獨(dú)立于Spring容器的緩存,則不受此配置影響。
(2)CacheConfig
標(biāo)注于類(lèi)上,更具體的說(shuō)是標(biāo)注于業(yè)務(wù)服務(wù)類(lèi)上。統(tǒng)一配置如下參數(shù)信息:
| 參數(shù) | 含義 | 使用說(shuō)明 |
|---|---|---|
cacheManager |
緩存管理器 | 缺省指首要的CacheManager |
cacheNames |
緩存名 | |
keyGenerator |
key值生成器 |
在類(lèi)上統(tǒng)一進(jìn)行配置,類(lèi)下的方法自動(dòng)繼承相應(yīng)的配置。
2、緩存注解
(1)Cacheable
添加緩存的核心注解,分兩種情況:一是對(duì)應(yīng)key值未有緩存數(shù)據(jù),先執(zhí)行方法,然后根據(jù)condition和unless條件決定是否添加緩存;二是對(duì)應(yīng)key值已有緩存,不執(zhí)行方法體,直接返回?cái)?shù)據(jù)。
參數(shù) keyGenerator 與 key 是互斥的,當(dāng) key 存在時(shí) keyGenerator 配置自動(dòng)失效。
- 基礎(chǔ)參數(shù)
| 參數(shù) | 含義 | 使用說(shuō)明 |
|---|---|---|
cacheManager |
緩存管理器 | 缺省指首要的CacheManager |
cacheNames |
緩存名 | |
keyGenerator |
key值生成器 | |
key |
key值 |
- 高級(jí)參數(shù)
| 參數(shù) | 含義 | 默認(rèn)值 | 使用說(shuō)明 |
|---|---|---|---|
condition |
緩存條件 | 指示滿足條件方執(zhí)行緩存操作,一般使用參數(shù)作為條件 | |
unless |
否定緩存 | 當(dāng)條件為 true ,方法的返回值不會(huì)被緩存 | |
sync |
同步狀態(tài) | false | 表示將方法執(zhí)行結(jié)果以何種方式存入緩存 |
(2)CachePut
更新緩存注解。不管對(duì)應(yīng)key值是否有緩存數(shù)據(jù),都執(zhí)行。
- 基礎(chǔ)參數(shù)
| 參數(shù) | 含義 | 使用說(shuō)明 |
|---|---|---|
cacheManager |
緩存管理器 | 缺省指首要的CacheManager |
cacheNames |
緩存名 | |
keyGenerator |
key值生成器 | |
key |
key值 |
- 高級(jí)參數(shù)
| 參數(shù) | 含義 | 使用說(shuō)明 |
|---|---|---|
condition |
緩存條件 | 指示滿足條件方執(zhí)行緩存操作,一般使用參數(shù)作為條件 |
unless |
否定緩存 | 當(dāng)條件為 true ,方法的返回值不會(huì)被緩存 |
(3)CacheEvict
主動(dòng)清除緩存注解。
- 基礎(chǔ)參數(shù)
| 參數(shù) | 含義 | 使用說(shuō)明 |
|---|---|---|
cacheManager |
緩存管理器 | 缺省指首要的CacheManager |
cacheNames |
緩存名 | |
keyGenerator |
key值生成器 | |
key |
key值 |
- 高級(jí)參數(shù)
| 參數(shù) | 含義 | 默認(rèn)值 | 使用說(shuō)明 |
|---|---|---|---|
condition |
緩存條件 | 指示滿足條件方執(zhí)行緩存操作,一般使用參數(shù)作為條件 | |
allEntries |
所有緩存 | false | 表示是否清空當(dāng)前CacheName對(duì)應(yīng)的所有緩存 |
beforeInvocation |
調(diào)用前 | false | 表示是否在方法調(diào)用前清空緩存 |
3、KeyGenerator
默認(rèn)情況下使用SimpleKeyGenerator鍵值生成器,當(dāng)不指定key值時(shí),根據(jù)生成器規(guī)則,將方法參數(shù)轉(zhuǎn)化為緩存Key值。