@(Java ThirdParty)[Spring Cache]
Spring Cache Abstraction
簡介
Spring Cache提供了對底層緩存使用的抽象,通過注解的方式使用緩存,減少了對原有的侵入性,通過一個抽象層,分離了不同后端緩存的實現,在不改變代碼的前提下,可以切換底層緩存的實現。
Cache只有應用於冪等性的方法,即同樣的輸入,返回同樣的數據(在數據沒有變更時)。
在多線程的情況下,由Cache底層實現類保存線程安全。
Cache 兩次讀取數據流程(第一次miss,第二次hit):
注解使用說明
Cacheable
@Cacheable
注解用於指示緩存該方法的返回數據。
該注解的屬性中,需要指定一個name,用於綁定到低層的緩存(比如,底層使用的是CurrentHashMap,那這個name就是用於指示到底是哪個Map,一般來說,一個方法或者類對應一個Map)
Key Generator
KeyGenerator
用於生成Cache Key,默認提供SimpleKeyGenerator計算方法如下:
- 如果沒有參數,就返回SimpleKey.EMPTY
- 如果有一個參數,就返回該參數實例
- 如果有多個方法,就返回一個SimpleKey,該實例包含了所有的參數
默認提供的Generator使用hashCode以及equals來計算,所以對於復雜的類,需要實現對應的方法。或者也可以通過自定義KeyGenerator來實現。(使用keyGenerator屬性來指定)
除了使用KeyGenerator外,還可以使用key屬性來指定(兩者只能使用一個,否則會拋異常)
Key屬性
通過SpEL來生成Key,如:
@Cacheable(cacheNames="books", key="#isbn")
public Book findBook(ISBN isbn, boolean check);
@Cacheable(cacheNames="books", key="#isbn.rawNumber")
public Book findBook(ISBN isbn, boolean check);
Cache Resolution
CacheResolver
Sync
Cache緩存的時候,如果多次同時調用,當沒有命中的時候,會直接調用方法計算,這會導致重復計算,以及緩存沒有生效,這時就需要采用同步的方式,一個方法調用,其余的在等待。
可以通過sync=“true”
屬性來指定(默認為false)
注:這個特性取決於底層的實現(在Cache Aop讀取流程中並沒有加鎖處理)
條件式緩存
當需要在特定參數情況下才緩存的時候,就可以使用。通過condition來計算,如果為true,則緩存,否則不緩存,如:
@Cacheable(cacheNames="books", condition="#name.length < 32")
public Book findBook(String name);
SpEL Cache表達式上下文
CachePut
@CachePut
用於更新緩存
注:不能和@Cacheable
同時使用。
CacheEvict
@CacheEvict
注解用於淘汰緩存,其中可以通過cacheNames和key屬性來淘汰指定的Entry,也可以使用cacheNames和allEntries=true來淘汰掉所有的Entries。
beforeInvocation屬性
這個屬性用於控制是在方法調用前還是調用后再淘汰緩存,如果是調用后,在拋出異常時,則不會淘汰(默認為false)。
這里也涉及了緩存寫淘汰策略。
Caching
@Caching
用於將多個操作組合起來,如CacheEvict和CachePut組合
CacheConfig
類級別的注解,用於定義一些該類的通用配置,可以被方法級別的配置覆蓋
三個層級配置:
- 全局配置,CacheManager/KeyGenerator
- 類級別配置
- 方法級別
開啟Cache注解功能
@EnableCaching
置於@Configuration
配置上,或者在XML加入配置:
<cache:annotation-driven />
注:如果把<cache:annotation-driven />
放在WebApplicationContext中的話,那就只會掃描controllers,而不是services
Cache存儲配置
Spring Cache提供了多個不同的存儲集成,使用的時候,只需要定義對應的CacheManager
即可。
如下:
- JDK ConcurrentMap-based Cache.(使用ConcurrentHashMap作為底層存儲)
- EhCache-base Cache
- Caffeine Cache
- Guava Cache
- GemFire-base Cache
- JSR-107 Cache
Spring Cache可以配置多個Cache實現(使用CompositeCacheManager
)
注:如果上述的集成都不滿足,則可以自定義實現,通過實現CacheManager
和Cache
即可。
Cache Aop執行流程
在下述的所有操作中,都沒有同步或者鎖的操作,即如果要實現相同query防止重復執行,則需要底層緩存庫支持。
注:這里會有並發問題,舉個例子:查詢個人信息。當緩存沒有命中的時候,會執行實際的方法,然后將結果緩存起來。在這中間,如果作了更新的操作,並且執行完CacheEvict,然后上述查詢結果再緩存起來,就會導致讀取到臟數據。所以緩存的時間也需要控制好。
參考資料
- spring-framework-reference - ch36
- spring cache 源碼