Spring @Cacheable 的使用小結(jié)
前言
@Cacheable 是 Spring 框架中用于方法級緩存的注解。它主要用于減少方法調(diào)用的次數(shù),通過緩存方法的返回結(jié)果來提高應(yīng)用程序的性能。
核心原理是,Spring 提供了統(tǒng)一的標(biāo)準(zhǔn)抽象,可以插拔式接入不同的緩存實(shí)現(xiàn)。但對于開發(fā)使用時(shí),無需關(guān)注底層使用哪套緩存源,上層使用時(shí)的都是標(biāo)準(zhǔn)一套方式,如 @Cacheable ...
這便是 Spring Cacheable 存在的價(jià)值與意義。
流程
作用
- 緩存結(jié)果:@Cacheable 注解的方法在第一次調(diào)用時(shí)會將結(jié)果緩存起來,后續(xù)調(diào)用相同參數(shù)的方法時(shí),會直接從緩存中獲取結(jié)果,而不再執(zhí)行方法體。
- 提高性能:通過減少重復(fù)計(jì)算和數(shù)據(jù)庫查詢等耗時(shí)操作,提高應(yīng)用程序的響應(yīng)速度和性能。
- 透明性:開發(fā)者無需顯式管理緩存,Spring 自動處理緩存的存儲和檢索。
原理
@Cacheable 的工作機(jī)制依賴于 Spring 的緩存抽象層。以下是其工作原理的關(guān)鍵點(diǎn):
- 緩存管理器:Spring 提供了多種緩存管理器(如 ConcurrentMapCacheManager、EhCacheCacheManager、RedisCacheManager 等),用于管理緩存的存儲和檢索。
- 緩存解析:當(dāng)帶有 @Cacheable 注解的方法被調(diào)用時(shí),Spring 會檢查緩存中是否存在對應(yīng)的結(jié)果。如果存在,則直接返回緩存結(jié)果;如果不存在,則執(zhí)行方法體并將結(jié)果存入緩存。
- 緩存鍵:默認(rèn)情況下,緩存鍵是根據(jù)方法參數(shù)自動生成的。可以通過 key 屬性自定義緩存鍵。
- 條件緩存:可以通過 condition 屬性指定條件表達(dá)式,只有滿足條件時(shí)才會緩存結(jié)果。
- 緩存命名:通過 value 或 cacheNames 屬性指定緩存的名稱,以便在不同的緩存中存儲結(jié)果。
用法
以下是 @Cacheable 的基本用法示例:
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
public class ProductService {
@Cacheable(value = "products", key = "#id")
public Product getProductById(Long id) {
...
// biz logic
...
}
}
關(guān)鍵屬性
- value/cacheNames:指定緩存的名稱。
- key:自定義緩存鍵的生成策略。
- condition:指定緩存條件,只有滿足條件時(shí)才會緩存結(jié)果。
- unless:指定條件表達(dá)式,只有不滿足條件時(shí)才會緩存結(jié)果。
配置
要使用 @Cacheable,需要在 Spring 配置中啟用緩存支持:
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableCaching
public class CacheConfig {
// 可以在這里配置緩存管理器
}
緩存抽象層
Spring 的緩存抽象層提供了一種統(tǒng)一的方式來管理不同的緩存實(shí)現(xiàn)。
它通過定義一組標(biāo)準(zhǔn)接口和注解,使得開發(fā)者可以輕松地在應(yīng)用程序中集成緩存功能,而無需關(guān)心底層緩存技術(shù)的具體實(shí)現(xiàn)。
這種抽象層的設(shè)計(jì)使得應(yīng)用程序可以在不同的緩存解決方案之間切換,而無需修改業(yè)務(wù)邏輯代碼。
緩存抽象層的核心組件
Cache 接口:
- 定義了緩存的基本操作,如獲取、放置和刪除緩存條目。
- 常用方法包括 get(Object key)、put(Object key, Object value) 和 evict(Object key)。
CacheManager 接口:
- 管理多個(gè) Cache 實(shí)例,提供對緩存的訪問。
- 負(fù)責(zé)根據(jù)緩存名稱獲取對應(yīng)的 Cache 實(shí)例。
- 常用方法包括 getCache(String name) 和 getCacheNames()。
CacheResolver 接口:
- 用于解析緩存的策略,決定使用哪個(gè)緩存。
- 可以自定義實(shí)現(xiàn)以滿足復(fù)雜的緩存解析需求。
CacheErrorHandler 接口:
- 定義了處理緩存操作異常的策略。
- 可以自定義實(shí)現(xiàn)以處理緩存操作中的異常情況。
緩存注解
Spring 提供了一組注解來簡化緩存操作:
- @Cacheable:用于標(biāo)記方法的返回結(jié)果可以被緩存。
- @CachePut:用于更新緩存,不影響方法的執(zhí)行。
- @CacheEvict:用于從緩存中移除一個(gè)或多個(gè)條目。
- @Caching:用于組合多個(gè)緩存操作注解。
緩存管理器
緩存管理器(CacheManager)是 Spring 緩存抽象層的核心組件之一。它負(fù)責(zé)管理應(yīng)用程序中的多個(gè)緩存實(shí)例,并提供對這些緩存的統(tǒng)一訪問接口。
通過緩存管理器,開發(fā)者可以輕松地在應(yīng)用程序中集成和管理緩存功能。
緩存管理器的核心功能
緩存實(shí)例管理:
- 緩存管理器負(fù)責(zé)創(chuàng)建和管理多個(gè)緩存實(shí)例。每個(gè)緩存實(shí)例通常對應(yīng)一個(gè)特定的緩存區(qū)域或命名空間。
緩存訪問接口:
- 提供統(tǒng)一的接口來訪問和操作緩存實(shí)例。開發(fā)者可以通過緩存管理器獲取特定名稱的緩存,并對其進(jìn)行操作。
緩存配置:
- 緩存管理器允許配置緩存的行為,如過期策略、存儲策略和序列化策略等。
常見的緩存管理器實(shí)現(xiàn)
Spring 提供了多種緩存管理器實(shí)現(xiàn),支持不同的緩存存儲技術(shù):
ConcurrentMapCacheManager:
- 基于 Java 的 ConcurrentHashMap 實(shí)現(xiàn)的簡單內(nèi)存緩存管理器。
- 適合開發(fā)和測試環(huán)境,不適合生產(chǎn)環(huán)境的分布式緩存需求。
EhCacheCacheManager:
- 支持 EhCache 的緩存管理器,適合需要持久化和高級緩存特性的場景。
RedisCacheManager:
- 支持 Redis 的緩存管理器,適合分布式緩存場景,提供高性能和可擴(kuò)展性。
CaffeineCacheManager:
- 支持 Caffeine 的緩存管理器,提供高性能的內(nèi)存緩存,適合需要低延遲的應(yīng)用。
GuavaCacheManager:
- 支持 Guava 的緩存管理器,適合簡單的內(nèi)存緩存需求。
默認(rèn)緩存管理器?
如果不顯示指定緩存管理器,系統(tǒng)會默認(rèn)使用哪個(gè)緩存管理器?
如果在 Spring 應(yīng)用中啟用了緩存功能(通過 @EnableCaching 注解),但沒有顯式配置緩存管理器,Spring 會使用默認(rèn)的緩存管理器。
具體來說,Spring Boot 會自動配置一個(gè)基于 ConcurrentMapCacheManager 的緩存管理器。
默認(rèn)緩存管理器:ConcurrentMapCacheManager
實(shí)現(xiàn):ConcurrentMapCacheManager 是基于 Java 的 ConcurrentHashMap 實(shí)現(xiàn)的簡單內(nèi)存緩存管理器。
特性:
- 線程安全:由于使用了 ConcurrentHashMap,它是線程安全的。
- 簡單易用:適合開發(fā)和測試環(huán)境,因?yàn)樗恍枰魏瓮獠恳蕾嚒?/li>
- 非持久化:緩存數(shù)據(jù)存儲在內(nèi)存中,應(yīng)用程序重啟后數(shù)據(jù)會丟失。
- 單節(jié)點(diǎn):不支持分布式緩存,僅適用于單節(jié)點(diǎn)應(yīng)用。
使用場景
- 開發(fā)和測試:由于其簡單性和易用性,ConcurrentMapCacheManager 非常適合在開發(fā)和測試階段使用。
- 小型應(yīng)用:對于不需要分布式緩存和持久化的簡單應(yīng)用,也可以使用這種默認(rèn)緩存管理器。
指定緩存管理器
當(dāng)然,最常見的、也是最推薦的是顯示指定緩存管理器。
以下是配置 RedisCacheManager 的示例:
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.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
@Configuration
@EnableCaching
public class RedisCacheConfig {
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(60)) // 設(shè)置緩存過期時(shí)間
.disableCachingNullValues()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()));
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(cacheConfiguration)
.build();
}
}
配置多個(gè)緩存管理器?
如果配置了多個(gè)緩存管理器,系統(tǒng)如何選擇?
在 Spring 應(yīng)用中,如果配置了多個(gè)緩存管理器,系統(tǒng)需要一種機(jī)制來選擇使用哪個(gè)緩存管理器。Spring 的緩存抽象
通常有幾種方式,如下:
選擇緩存管理器的機(jī)制
默認(rèn)緩存管理器:
- 如果沒有特別指定,Spring 會使用默認(rèn)的緩存管理器。默認(rèn)緩存管理器通常是通過 @Primary 注解標(biāo)記的緩存管理器。
- 如果沒有標(biāo)記 @Primary,Spring 會嘗試使用第一個(gè)找到的緩存管理器。
自定義 CacheResolver:
- 你可以實(shí)現(xiàn) CacheResolver 接口來自定義緩存解析邏輯。通過自定義 CacheResolver,可以根據(jù)方法參數(shù)、注解屬性或其他上下文信息來動態(tài)選擇緩存管理器。
- 自定義的 CacheResolver 可以通過 @Cacheable、@CachePut 和 @CacheEvict 注解的 cacheResolver 屬性來指定。
自定義處理器:
@Configuration
public class CustomCacheResolverConfig {
@Bean
public CacheResolver customCacheResolver(CacheManager memoryCacheManager, CacheManager redisCacheManager) {
// 自定義邏輯來選擇緩存管理器
return new SimpleCacheResolver(memoryCacheManager); // 示例中簡單使用內(nèi)存緩存
}
}
使用緩存時(shí),指定處理器:
@Service
public class ProductService {
@Cacheable(value = "products", key = "#id", cacheResolver = "customCacheResolver")
public Product getProductById(Long id) {
// ...
}
}
- 使用緩存時(shí),指定緩存管理器 cacheManager
@Cacheable(cacheNames = "getItemDetail", cacheManager = "simpleCacheManager", unless = "#result.size() == 0")
public Collection<BillItemDTO> getItemDetail() {
// ...
}
如果有多個(gè)緩存管理器,這里推薦指定緩存管理器,更加直觀易懂.
總結(jié)
@Cacheable 是一個(gè)強(qiáng)大的注解,用于在 Spring 應(yīng)用中實(shí)現(xiàn)方法級緩存。通過緩存方法的返回結(jié)果,可以顯著提高應(yīng)用程序的性能。
Spring 提供了靈活的緩存管理機(jī)制,支持多種緩存存儲方案,并允許開發(fā)者自定義緩存鍵和條件。
Spring 通過抽離抽象層,支持多套不同緩存,我們也可以同時(shí)使用多套不同的緩存以滿足不同需求。
到此這篇關(guān)于Spring @Cacheable 的使用小結(jié)的文章就介紹到這了,更多相關(guān)Spring @Cacheable 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Myeclipse工程發(fā)布時(shí)端口占用問題的解決方法
這篇文章主要介紹了Myeclipse工程發(fā)布時(shí)端口占用問題的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12
Spring Boot項(xiàng)目中結(jié)合MyBatis實(shí)現(xiàn)MySQL的自動主從切換功能
這篇文章主要介紹了Spring Boot項(xiàng)目中結(jié)合MyBatis實(shí)現(xiàn)MySQL的自動主從切換功能,本文分步驟給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2025-04-04
Java實(shí)現(xiàn)SSL雙向認(rèn)證的方法
這篇文章主要介紹了Java實(shí)現(xiàn)SSL雙向認(rèn)證的方法,實(shí)例分析了ssl認(rèn)證的原理與相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2016-08-08
在Android中使用WebView在線查看PDF文件的方法示例
在Android應(yīng)用開發(fā)中,有時(shí)我們需要在客戶端展示PDF文件,以便用戶可以閱讀或交互,這篇文章主要介紹了在Android中使用WebView在線查看PDF文件的方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-09-09
Java的Comparable,Comparator和Cloneable三大接口詳解
這篇文章主要為大家詳細(xì)介紹了Java的Comparable,Comparator和Cloneable的接口,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-03-03
Mac下eclipse項(xiàng)目根目錄沒有.setting文件夾的解決方案
文章介紹了如何通過修改項(xiàng)目根路徑下.setting文件夾中的org.eclipse.wst.common.project.facet.core.xml文件來解決Web版本問題2026-02-02

