简介
Spring @Cacheable 注解
@Cacheable
是什么
@Cacheable
是 Spring Framework 提供的一个注解,用于方法级别的缓存管理。当一个被标注为 @Cacheable
的方法被调用时,它会先检查缓存中是否有对应的结果。如果有,则直接返回缓存结果,而不会执行方法逻辑。如果没有,则执行方法逻辑并将结果存入缓存,以便下次调用时直接使用缓存值。
作用
- 提升性能:避免重复调用耗时的计算或 I/O 操作(如数据库查询或远程调用)。
- 减少资源消耗:减少系统对外部依赖(如数据库、API)的访问频率。
- 简单易用:通过注解配置,无需显式管理缓存逻辑。
参数解析
java
@Cacheable(
cacheNames = ..., // 缓存的名字(可理解为缓存的分类)
key = ..., // 缓存的键(默认使用方法参数作为键)
unless = ..., // 条件表达式,返回 true 时不会缓存
condition = ... // 条件表达式,返回 true 时才缓存
)
cacheNames
: 指定缓存名称,用于区分不同的缓存空间。key
: 自定义缓存键的生成规则,支持 SpEL(Spring Expression Language)。unless
: 返回结果满足条件时,不存入缓存。condition
: 满足条件时,才会存入缓存。sync
: 如果为true
,则多个线程同时访问会先锁定,确保只执行一次计算。
Caffeine 本地缓存
Caffeine 是一个高性能、本地缓存库,提供类似于 Guava Cache 的功能,并且性能更优。想了解跟多可以自行百度,这里不做过多介绍哈(感谢支持)
Caffeine 和 Spring Cache 实现本地缓存
1. 添加 Maven 依赖
在 pom.xml
中添加以下依赖:
xml
<dependencies>
<!-- Spring Cache Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- Caffeine Cache -->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.1.7</version> <!-- 使用最新稳定版本 -->
</dependency>
</dependencies>
2.配置类 LocalCacheConfig
java
import com.github.benmanes.caffeine.cache.Caffeine;
import com.atom.utils.CollectionUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
@Configuration
public class LocalCacheConfig {
public final static String PRODUCT_CACHE = "PRODUCT_CACHE";
@Bean
public Cache flashRedisFallbackCache(CacheManager cacheManager) {
CaffeineCache localCache = new CaffeineCache(PRODUCT_CACHE, Caffeine.newBuilder()
.recordStats()
.expireAfterWrite(300, TimeUnit.SECONDS)
.initialCapacity(10000)
.maximumSize(10000).build());
reInitCacheManager(cacheManager, localCache);
return localCache;
}
/**
* SimpleCacheManager 中的缓存实例是初始化时一次性加载的,需要重新初始化一下CacheManager,将自定义cache池加入CacheManager
*/
private void reInitCacheManager(CacheManager cacheManager, Cache cache) {
SimpleCacheManager simpleCacheManager = (SimpleCacheManager) cacheManager;
Collection<String> cacheNames = simpleCacheManager.getCacheNames();
ArrayList<Cache> caches = new ArrayList<>();
if (CollectionUtils.isNotEmpty(cacheNames)) {
cacheNames.forEach(cacheName -> caches.add(simpleCacheManager.getCache(cacheName)));
}
caches.add(cache);
((SimpleCacheManager) cacheManager).setCaches(caches);
((SimpleCacheManager) cacheManager).initializeCaches();
}
}
3. 在业务方法中使用缓存注解
使用 Spring 提供的缓存注解(如 @Cacheable
、@CachePut
、@CacheEvict
)来实现缓存的读写操作。
示例 1: 使用 @Cacheable
java
@Service
public class ProductService {
@Cacheable(cacheNames = "PRODUCT_CACHE", key = "'product:' + #productId")
public ProductDTO getProductById(String productId) {
// 模拟查询数据库
return productRepository.findProductById(productId);
}
}
示例 2: 更新缓存 (@CachePut
)
java
@CachePut(cacheNames = "PRODUCT_CACHE", key = "'product:' + #productId.id")
public ProductDTO updateProduct(ProductDTO product) {
productRepository.updateProduct(product);
return product;
}
示例 3: 清除缓存 (@CacheEvict
)
java
@CacheEvict(cacheNames = "PRODUCT_CACHE", key = "'product:' + #productId")
public void deleteProduct(String productId) {
productRepository.deleteProductById(productId);
}
4. 验证缓存是否生效
验证缓存时,可以通过以下方式检查:
-
日志输出 :启用 Spring Cache 的 debug 日志,查看缓存操作的记录。
在
application.yml
中添加:yamllogging: level: org.springframework.cache: DEBUG
-
统计信息 :通过
Caffeine.newBuilder().recordStats()
启用统计信息,并使用以下代码查看缓存命中率等:javaCaffeineCache storeCache = (CaffeineCache) cacheManager.getCache("STORE_CACHE"); System.out.println(storeCache.getNativeCache().stats());
总结
通过 Caffeine 和 Spring Cache 的集成简单易用,通过注解配置,无需显式管理缓存逻辑。在调用数据的方法上加可以减少重复调用问题,降低被调用方的压力,也可结合 Redis
快速实现多级缓存,解决热点数据问题。更多妙用,开发者可以继续探索,感谢支持,下期再见👋