SpringBoot整合SpringCache使用緩存
文章目錄
- SpringBoot整合SpringCache使用緩存
- 1.介紹
- 2.SpringBoot整合
- 1.導入xml依賴
- 2.配置yml
- 3.使用@EnableCaching啟用SpringCache
- 4.@Cacheable
- 5.@CachePut
- 6.@CacheEvict
- 7. @Caching
- 8.@CacheConfig
- 3.其他屬性配置
- 1.`keyGenerator` 屬性
- 2. `cacheManager` 屬性
- 3.`cacheResolver` 屬性
- 4.CacheManagerCustomizer
1.介紹
Spring Cache 提供了 Cache
和 CacheManager
接口來統一管理不同的緩存技術。Cache
是緩存的抽象,CacheManager
負責管理多個 Cache
實例。Spring Cache 支持多種緩存實現,包括:
- ConcurrentHashMap:默認的緩存實現,適用于簡單的本地緩存。
- Redis:基于 Redis 的分布式緩存,適用于高并發場景。
- Ehcache:符合 JSR-107 標準的緩存實現,支持二級緩存。
- Caffeine:基于 Java 8 的高性能緩存庫,適用于需要高性能的場景。
- JSR-107:支持 JSR-107 標準的緩存實現。
2.SpringBoot整合
本文基于springboot2.7版本測試
1.導入xml依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
2.配置yml
spring:cache:cache-names: usertype: redisredis:#緩存前綴key-prefix: moshangshang_#是否啟用緩存統計信息。enable-statistics: false#是否允許緩存 null 值。cache-null-values: true#寫入 Redis 時是否使用 key prefix。use-key-prefix: trueredis:port: 6379host: 127.0.0.1password: rootlettuce:pool:max-active: 20 #連接池最大連接數(使用負值表示沒有限制)max-idle: 8 #連接池中的最大空閑連接min-idle: 5 # 連接池中的最小空閑連接timeout: 6000 #連接超時時長(毫秒)
如果cache-null-values:屬性啟用不能緩存null值,則緩存null時會拋出下方異常
java.lang.IllegalArgumentException: Cache 'user' does not allow 'null' values. Avoid storing null via '@Cacheable(unless="#result == null")' or configure RedisCache to allow 'null' via RedisCacheConfiguration.
cache-names屬性說明:
用于管理全的緩存key的全局配置,多個用逗號分割,比如 cache-names: user; use-key-prefix: false,則表示 @Cacheable(cacheNames = "user“)之類的注解不會使用key-prefix指定的緩存前綴,未配置的緩存名稱則采用默認全局配置
3.使用@EnableCaching啟用SpringCache
@SpringBootApplication
@EnableCaching
public class CacheApplication {public static void main(String[] args) {SpringApplication.run(CacheApplication.class, args);}
}
4.@Cacheable
@Cacheable 用于標記方法或類,表示該方法的返回值可以被緩存。
當方法執行前,Spring 會檢查緩存中是否存在相同 key 的緩存元素,如果存在則直接返回,否則執行方法并將結果存入緩存。
@Cacheable 的方法必須為 public:如果方法不是 public 的,Spring 無法通過代理來訪問緩存。
- value 或 cacheNames:指定緩存的名稱,可以是單個字符串或字符串數組。
- key:指定緩存的鍵,可以使用 SpEL 表達式來定義。
- condition:指定緩存的條件,只有當條件為 true 時,才會從緩存中獲取結果。
- unless:指定不將結果放入緩存的條件,即使結果存在,也不會被緩存。
- sync:是否使用同步方式獲取緩存,避免多個線程同時執行方法。
- 在某些場景下,需要確保緩存和數據庫的一致性,可以使用 @Cacheable 的 sync 屬性來啟用同步更新。且在多線程環境下確保只有一個線程執行查詢。
/*** 根據id查詢用戶信息* 生成的key為moshangshang_user::38*/@GetMapping("/query/{id}")@Cacheable(cacheNames = "user",key = "#id",unless = "#result == null")public User getById(@PathVariable Long id){return userService.getById(id);}
5.@CachePut
@CachePut 用于標記方法,表示每次調用該方法時都會執行并存入緩存。
它總是會執行方法,并將結果添加到緩存中,不會檢查緩存中是否存在相同 key 的緩存元素。
- value 或 cacheNames:指定緩存的名稱,可以是單個字符串或字符串數組。
- key:指定緩存的鍵,可以使用 SpEL 表達式來定義。
- condition:指定緩存的條件,只有當條件為 true 時,才會從緩存中獲取結果。
- unless:指定不將結果放入緩存的條件,即使結果存在,也不會被緩存。
@PostMapping("/save")@CachePut( key = "#user.id")public User updateUser(User user) {userService.saveOrUpdate(user);return user;}
6.@CacheEvict
@CacheEvict 用于標記方法,表示該方法執行時會清除緩存中的數據。
@CacheEvict 在方法執行期間拋出異常不會清空緩存:如果方法執行過程中拋出異常,@CacheEvict 的 allEntries 屬性不會生效。
它可以用于刪除緩存中的所有鍵值對,也可以用于清除特定的 key。
- value 或 cacheNames:指定緩存的名稱,可以是單個字符串或字符串數組。
- key:指定緩存的鍵,可以使用 SpEL 表達式來定義。
- condition:指定緩存的條件,只有當條件為 true 時,才會從緩存中獲取結果。
- beforeInvocation:是否在方法執行前清除緩存,為 true 時在方法執行前清除緩存。
- allEntries:是否清除所有緩存條目,為 true 時清除所有緩存。
/*** @CacheEvict 在方法執行期間拋出異常不會清空緩存:如果方法執行過程中拋出異常,@CacheEvict 的 allEntries 屬性不會生效。* @CacheEvict 用于標記方法,表示該方法執行時會清除緩存中的數據。* 它可以用于刪除緩存中的所有鍵值對,也可以用于清除特定的 key。* value 或 cacheNames:指定要清除的緩存名稱。* key:指定要清除的緩存鍵,可以使用 SpEL 表達式來定義。* allEntries:是否清除所有緩存條目,為 true 時清除所有緩存。* beforeInvocation:是否在方法執行前清除緩存,為 true 時在方法執行前清除緩存。* condition:指定清除緩存的條件,只有當條件為 true 時,才會清除緩存。*/@GetMapping("/delete/{id}")@CacheEvict(key = "#id", allEntries = false)public void deleteUser(@PathVariable Long id) {userService.removeById(id);}
7. @Caching
@Caching 是一個組合注解,可以同時應用多個其他注解,表示該方法會同時執行 @Cacheable、@CachePut 和 @CacheEvict 的操作。
@GetMapping("/save/caching")@Caching(cacheable = @Cacheable( key = "#user.id"),put = @CachePut( key = "#user.id"),evict = @CacheEvict( key = "#user.id"))public User saveUser(User user) {userService.save(user);return user;}
8.@CacheConfig
@CacheConfig 用于在類上設置公共的緩存配置,避免在每個方法上重復配置。
/*** @CacheConfig 用于在類上設置公共的緩存配置,避免在每個方法上重復配置。*/
@RestController
@AllArgsConstructor
@RequestMapping("cache")
@CacheConfig(cacheNames = "user")
public class CacheController {private final IUserService userService;@GetMapping("/query/{id}")@Cacheable(key = "#id",unless = "#result == null")public User getById(@PathVariable Long id){return userService.getById(id);}
}
3.其他屬性配置
1.keyGenerator
屬性
keyGenerator
屬性用于指定默認的鍵生成器(Key Generator)。如果在方法上未顯式指定 key
屬性,則使用該屬性值作為默認的鍵生成器。
1.配置生成器
@Configuration
public class CacheConfig {@Bean(name = "customKeyGenerator")public KeyGenerator keyGenerator() {return (target, method, params) -> method.getName() + "[" + Arrays.asList(params) + "]";}
}
等同于
@Bean(name = "customKeyGenerator")public KeyGenerator keyGenerator() {return new KeyGenerator() {@Overridepublic Object generate(Object target, Method method, Object... params) {return method.getName() + "[" + Arrays.asList(params) + "]";}};}
2.使用
生成的key為moshangshang_user::getById[[39]]
@Cacheable(unless = "#result == null",keyGenerator = "customKeyGenerator")public User getById(@PathVariable Long id){return userService.getById(id);}
2. cacheManager
屬性
cacheManager
屬性用于指定當前使用的 CacheManager
實現類的名稱。CacheManager
是 Spring 定義的一個接口,用于管理緩存(Cache)的創建和配置。Spring 提供了多種 CacheManager
的實現,例如 ConcurrentMapCacheManager
、EhCacheCacheManager
、CaffeineCacheManager
等。通過設置 cacheManager
屬性,可以指定使用哪種緩存管理器來管理緩存。
創建自定義的緩存管理器
@Configuration
public class CacheConfig {@Beanpublic ConcurrentMapCacheManager mapCacheManager() {return new ConcurrentMapCacheManager("user-map","user");}}
cacheManager()
方法返回了一個 ConcurrentMapCacheManager
實例,并且指定了緩存名稱。這個 CacheManager
將被用于管理名為 指定的緩存。
/*** 執行的是mapCacheManager的緩存管理器*/@GetMapping("/manger/map/query/{id}")@Cacheable(cacheManager = "mapCacheManager")public User getRedisMangerById(@PathVariable Long id){return userService.getById(id);}
3.cacheResolver
屬性
cacheResolver
屬性用于指定一個自定義的 CacheResolver
實現。默認情況下,Spring 使用 SimpleCacheResolver
來解析緩存操作。通過自定義 CacheResolver
,可以實現更復雜的緩存邏輯,例如根據方法名動態選擇緩存名稱或緩存管理器。
cacheManager
和cacheResolver
是互斥的:如果同時指定了cacheManager
和cacheResolver
,Spring 會拋出異常,因為CacheResolver
的實現會忽略自定義的CacheManager
。- 自定義
CacheResolver
的靈活性:通過自定義CacheResolver
,可以實現更靈活的緩存管理,例如根據方法名、參數或上下文動態選擇緩存名稱或緩存管理器 。 - Spring 4.1 及以上版本:從 Spring 4.1 開始,
@Cacheable
、@CachePut
、@CacheEvict
等注解的value
屬性不再是強制性的,因為CacheResolver
可以提供緩存名稱信息
自定義緩存解析器
getById方法取user緩存名稱下數據,其他取user-map下數據
public class CustomCacheResolver implements CacheResolver {private final ConcurrentMapCacheManager concurrentMapCacheManager;private final RedisCacheManager redisCacheManager;public CustomCacheResolver(ConcurrentMapCacheManager concurrentMapCacheManager, RedisCacheManager redisCacheManager) {this.concurrentMapCacheManager = concurrentMapCacheManager;this.redisCacheManager = redisCacheManager;}@Overridepublic Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {Collection<Cache> caches = new ArrayList<>();if (context.getTarget().getClass() == CacheController.class) {if (context.getMethod().getName().equals("getRedisById")) {caches.add(redisCacheManager.getCache("user"));}else {caches.add(concurrentMapCacheManager.getCache("user-map"));}}return caches;}
}
配置自定義緩存管理器并注冊緩存解析器
配置了自定義的CacheManager會導致yml里面的相關配置失效(任何一個都會,比如指定map的緩存管理器,yml配redis,則redis的配置也不生效)
@Beanpublic ConcurrentMapCacheManager mapCacheManager() {return new ConcurrentMapCacheManager("user-map","user");}@Primary@Beanpublic RedisCacheManager redisCacheManager(RedisTemplate<String, Object> redisTemplate) {return RedisCacheManager.builder(Objects.requireNonNull(redisTemplate.getConnectionFactory())).cacheDefaults(RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10)) // 設置默認緩存過期時間為10分鐘.disableCachingNullValues()) // 禁用緩存空值.withInitialCacheConfigurations(initialCacheConfigurations()) // 設置特定緩存的配置.build();}private Map<String, RedisCacheConfiguration> initialCacheConfigurations() {Map<String, RedisCacheConfiguration> initialConfigurations = new HashMap<>();// 設置特定緩存的過期時間initialConfigurations.put("user", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1)) // 設置特定緩存的過期時間為1小時.disableCachingNullValues());return initialConfigurations;}@Beanpublic CacheResolver customCacheResolver(ConcurrentMapCacheManager concurrentMapCacheManager,RedisCacheManager redisCacheManager) {return new CustomCacheResolver(concurrentMapCacheManager,redisCacheManager);}
測試
/*** 執行的是RedisCacheManager的緩存管理器*/@GetMapping("/resolver/redis/query/{id}")@Cacheable(unless = "#result == null",cacheResolver = "customCacheResolver")public User getRedisById(@PathVariable Long id){return userService.getById(id);}/*** 執行的是ConcurrentMapCacheManager的緩存管理器*/@GetMapping("/resolver/map/query/{id}")@Cacheable(cacheNames = "user-map",unless = "#result == null",cacheResolver = "customCacheResolver")public User getMapCacheById(@PathVariable Long id){return userService.getById(id);}
4.CacheManagerCustomizer
CacheManagerCustomizer
是一個用于在緩存管理器初始化之前對其進行自定義配置的接口。通過實現該接口的 Bean,可以對緩存管理器進行定制,例如設置緩存名稱、是否允許緩存空值、設置緩存過期時間等。
- 自定義緩存配置:
CacheManagerCustomizer
允許在緩存管理器初始化之前對緩存進行配置,例如設置緩存名稱、過期時間、序列化方式等。這使得開發者可以針對不同的緩存需求進行靈活配置。 - 覆蓋默認配置:如果使用了
CacheManagerCustomizer
,那么application.yml
或application.properties
中的緩存配置將不會生效,因為CacheManagerCustomizer
會覆蓋默認的配置 。 - 支持多種緩存類型:
CacheManagerCustomizer
不僅適用于ConcurrentMapCacheManager
,還可以用于其他類型的緩存管理器,如RedisCacheManager
、CaffeineCacheManager
等。通過實現CacheManagerCustomizer
接口,可以對不同類型的緩存管理器進行統一的配置 。 - 提供回調機制:
CacheManagerCustomizer
提供了一個customize
方法,該方法會在緩存管理器初始化之前被調用,允許開發者對緩存管理器進行定制。例如,可以設置緩存名稱、允許或禁止緩存空值等 。
@Bean
public CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {return new CacheManagerCustomizer<ConcurrentMapCacheManager>() {@Overridepublic void customize(ConcurrentMapCacheManager cacheManager) {cacheManager.setCacheNames(Arrays.asList("user"));cacheManager.setAllowNullValues(false); // 禁用緩存空值}};
}@Beanpublic RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() {return (builder) -> {builder.cacheDefaults(RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10)) // 默認過期時間為 10 分鐘.disableCachingNullValues()); // 禁用緩存空值};}
如果配置了自定義的緩存管理器(redisCacheManager),則CacheManagerCustomizer將不生效