Spring Cache 详细讲解
Spring Cache 是 Spring 框架提供的缓存抽象层,通过统一的 API 和注解简化缓存操作,支持多种缓存实现(如 Redis、EhCache、Caffeine 等)。其核心目标是减少重复计算,提升系统性能,同时保持代码简洁性。
1. 核心概念
(1) 缓存抽象接口
Spring Cache 定义了一套标准接口,与具体缓存实现解耦:
-
Cache
:代表一个缓存实例(如 Redis 的一个键空间)。 -
CacheManager
:管理多个Cache
实例。 -
KeyGenerator
:生成缓存键的策略。 -
CacheResolver
:动态解析使用的缓存。
(2) 支持的缓存实现
-
本地缓存:Caffeine、EhCache、ConcurrentMapCache
-
分布式缓存:Redis、Memcached、Hazelcast
-
其他:JCache(JSR-107)、GemFire
2. 核心注解
(1) @Cacheable
-
用途:标记方法的返回值需要缓存。
-
触发条件:方法执行前检查缓存,若存在则直接返回结果,否则执行方法并缓存结果。
-
关键参数:
-
value
/cacheNames
:指定缓存名称(对应CacheManager
中的缓存实例)。 -
key
:自定义缓存键(支持 SpEL 表达式)。 -
condition
:缓存条件(满足条件才缓存)。 -
unless
:排除条件(满足条件不缓存)。
-
示例:
@Cacheable(value = "users", key = "#id", unless = "#result == null")
public User getUserById(Long id) {
return userRepository.findById(id).orElse(null);
}
(2) @CachePut
-
用途:更新缓存,无论缓存是否存在,都会执行方法并缓存结果。
-
适用场景:数据更新后强制刷新缓存。
示例:
@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {
return userRepository.save(user);
}
(3) @CacheEvict
-
用途:删除缓存条目。
-
关键参数:
-
allEntries
:是否清空整个缓存(默认false
)。 -
beforeInvocation
:是否在方法执行前清除缓存(默认false
,即方法执行后清除)。
-
示例:
@CacheEvict(value = "users", key = "#id")
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
(4) @Caching
-
用途:组合多个缓存操作。
-
示例:
@Caching(
cacheable = @Cacheable(value = "users", key = "#username"),
evict = @CacheEvict(value = "tokens", key = "#username")
)
public User getUserByUsername(String username) {
// ...
}
(5) @CacheConfig
-
用途:在类级别统一配置缓存的公共属性(如
cacheNames
、keyGenerator
)。 -
示例:
@CacheConfig(cacheNames = "products")
public class ProductService {
@Cacheable
public Product getProduct(Long id) { ... }
}
3. 配置与集成
(1) 启用缓存
在 Spring Boot 主类或配置类上添加 @EnableCaching
:
@SpringBootApplication @EnableCaching public class MyApp { ... }
(2) 选择缓存实现
以 Caffeine(高性能本地缓存)为例:
-
添加依赖:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
运行 HTML
-
配置缓存策略:
yaml
# application.yml
spring:
cache:
type: caffeine
caffeine:
spec: maximumSize=500, expireAfterWrite=10m
(3) 自定义 KeyGenerator
实现 KeyGenerator
接口:
public class CustomKeyGenerator implements KeyGenerator {
@Override
public Object generate(Object target, Method method, Object... params) {
return method.getName() + "_" + Arrays.toString(params);
}
}
注册到 Spring 容器:
@Configuration
public class CacheConfig {
@Bean
public KeyGenerator customKeyGenerator() {
return new CustomKeyGenerator();
}
}
使用自定义 KeyGenerator:
@Cacheable(value = "users", keyGenerator = "customKeyGenerator")
public User getUser(Long id) { ... }
4. 高级特性
(1) 条件缓存
通过 condition
和 unless
动态控制缓存行为:
@Cacheable(value = "users", key = "#id",
condition = "#id > 1000",
unless = "#result.age < 18")
public User getUser(Long id) { ... }
(2) 缓存同步
多线程环境下,使用 sync
参数同步缓存生成:
@Cacheable(value = "users", key = "#id", sync = true)
public User getUser(Long id) { ... }
(3) 多级缓存
结合本地缓存与分布式缓存(如 Caffeine + Redis):
-
本地缓存用于高频访问数据。
-
分布式缓存用于数据共享和持久化。
5. 最佳实践
(1) 缓存粒度控制
-
细粒度缓存:缓存单个对象(如用户信息)。
-
粗粒度缓存:缓存集合或复杂查询结果(需注意数据一致性)。
(2) 缓存穿透/击穿/雪崩防护
-
穿透:缓存空值(
unless = "#result == null"
)。 -
击穿:加锁(
sync = true
)或使用分布式锁。 -
雪崩:设置随机过期时间。
(3) 数据一致性
-
写策略:使用
@CachePut
或@CacheEvict
保证缓存与数据库同步。 -
事务支持:将缓存操作与事务绑定(需配置
TransactionAwareCacheManagerProxy
)。
6. 调试与监控
(1) 日志输出
在 application.properties
中启用缓存日志:
properties
logging.level.org.springframework.cache=TRACE
(2) 监控指标
Spring Boot Actuator 提供缓存指标:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
运行 HTML
访问 /actuator/caches
查看缓存信息。
总结
Spring Cache 通过注解和抽象层简化了缓存集成,开发者只需关注业务逻辑,无需深入底层实现细节。合理使用缓存可显著提升系统性能,但需注意数据一致性和缓存策略的设计。对于复杂场景,可结合多种缓存实现(如本地缓存 + Redis)实现多级缓存架构。