当前位置: 首页 > news >正文

Spring Boot :采用 Spring Cache 注解方式集成 Redis

一、项目概述

本实战教程将演示如何在 Spring Boot 项目中通过 Spring Cache 注解方式集成 Redis,实现高效的数据缓存功能。我们将创建一个简单的用户管理系统,展示各种缓存注解的使用方法。

【工程增强说明】

Spring Cache 本质上是一个缓存抽象层,它并不关心你底层用的是 Redis、EhCache 还是 Caffeine,它只定义了:

• CacheManager
• Cache
• CacheOperation

真正决定缓存行为的是你配置的 CacheManager 实现,而我们这里选择的是:

RedisCacheManager

这意味着你的缓存具备:
在这里插入图片描述

本项目适合:

• 中大型 Spring Boot 后端服务
• 分布式系统缓存标准模板
• 公司级缓存规范示例

【生产定位】

这不是“Hello Redis”,而是:

可以直接拿去当公司缓存架构样板的工程模板。

二、环境准备

2.1 依赖配置

<!-- pom.xml --><?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.1.0</version><relativePath/></parent><groupId>com.example</groupId><artifactId>redis-cache-demo</artifactId><version>1.0.0</version><properties><java.version>17</java.version></properties><dependencies><!-- Spring Boot Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring Boot Data Redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- Spring Boot Cache --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency><!-- Redis连接池 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency><!-- Lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- 单元测试 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- 缓存注解处理器 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency></dependencies></project>

【生产补充:这几项依赖的真实职责】
在这里插入图片描述

【版本选择说明】

你用的是:

Spring Boot 3.1.0 + Java 17

这意味着:

• Spring Framework 6.x
• Jakarta 命名空间
• 默认使用 Lettuce 客户端
• Redis 7 完美适配

是 当前主流生产版本组合,非常优秀。

2.2 Redis 配置

spring:
application:
name: redis-cache-demo
redis:
host: localhost
port: 6379
password: 123456
database: 0
timeout: 2000ms
lettuce:
pool:
max-active: 8
max-wait: -1ms
max-idle: 8
min-idle: 0
cache:
type: redis
redis:
time-to-live: 600000
cache-null-values: true
key-prefix: "CACHE:"
use-key-prefix: true

【生产级参数解读】

在这里插入图片描述

【生产建议版】

生产环境更推荐:

spring:
cache:
redis:
time-to-live: 1800000
cache-null-values: false
key-prefix: "PROD_CACHE:"

三、核心代码实现

这一部分是整篇文章的灵魂。
Spring Cache 用得好不好,80% 都取决于这里的设计是否“工程化”。

3.1 缓存配置类

@Configuration
@EnableCaching
public class RedisCacheConfig {
/**
* 自定义Redis缓存配置
*/
@Bean
public RedisCacheConfiguration redisCacheConfiguration() {
return RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10))  // 默认缓存10分钟
.disableCachingNullValues()  // 不缓存null值
.serializeKeysWith(RedisSerializationContext.SerializationPair
.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
}
/**
* 自定义缓存管理器配置
* 可以为不同的缓存名称设置不同的过期时间
*/
@Bean
public RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() {
return builder -> builder
.withCacheConfiguration("userCache",
RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(5))
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer())))
.withCacheConfiguration("productCache",
RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30))
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer())))
.withCacheConfiguration("shortCache",
RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(30)));
}
}

【工程级解读】

这段代码做了三件非常关键的事:
在这里插入图片描述

【生产补充 1:为什么必须统一序列化?】

如果你不显式指定:

.serializeValuesWith(...)

Spring Boot 3 默认会使用:

JdkSerializationRedisSerializer

问题是:

• Redis 里是二进制,看不懂
• Java 类变动就反序列化失败
• 跨语言无法使用

而你现在用的是:

GenericJackson2JsonRedisSerializer

这是生产最优解之一:
在这里插入图片描述

【生产补充 2:CacheName 的设计就是“缓存分区”】

你现在的:

userCache
productCache
shortCache

本质等价于:
在这里插入图片描述

这就是缓存层的领域模型分区设计。

【高级建议:TTL 加随机,防雪崩】

生产建议:

Duration base = Duration.ofMinutes(10);
long random = ThreadLocalRandom.current().nextLong(60);
.entryTtl(base.plusSeconds(random))

避免大量 Key 同时失效。

3.2 实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
private Long id;
private String username;
private String email;
private Integer age;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}

【生产补充:Serializable 不是给 Redis 用的】

JSON 序列化不需要 Serializable,
这个接口主要用于:

• Session
• RPC
• JVM 内对象传输

保留它是良好习惯,但不要误以为 Redis 依赖它。

3.3 服务层实现(缓存注解体系实战)
这一节是整篇最重要的一节,你这里已经写得非常专业。

3.3.1 @Cacheable:读缓存标准模型

@Cacheable(key = "'user:' + #id", unless = "#result == null")
public User getUserById(Long id) {
log.info("从数据库查询用户: {}", id);
simulateSlowService();
return userDatabase.get(id);
}

【缓存模型解释】

这是标准的:

Cache Aside Pattern

流程:

  1. 先查缓存
  2. 缓存没有 → 查 DB
  3. 放入缓存
  4. 返回结果

这是互联网最经典缓存模式。

【生产级 Key 设计规范】

你现在的 Key:

CACHE:userCache::user:123

完整结构是:

{前缀}:{CacheName}::{业务Key}

这是非常优秀的企业级规范。

3.3.2 @CachePut:更新必写缓存

@CachePut(key = "'user:' + #user.id")
public User updateUser(User user) {
log.info("更新用户: {}", user.getId());
user.setUpdateTime(LocalDateTime.now());
userDatabase.put(user.getId(), user);
return user;
}

【生产风险提示】

@CachePut 在高并发下存在一个风险:

如果数据库写成功,但 Redis 写失败,会出现数据不一致。

生产环境建议:

• 关键路径:DB 成功后 → 再删缓存
• 再由下一次查询回填缓存(双删模式)

即:

写 DB → 删除缓存 → 读请求触发重建
而不是直接 @CachePut 覆盖。

3.3.3 @CacheEvict:缓存失效治理

@CacheEvict(key = "'user:' + #id")
public void deleteUserById(Long id) {
userDatabase.remove(id);
}

【生产增强:双删策略】

  1. 删除 DB
  2. 删除缓存
  3. 延迟 500ms 再删一次

防止并发回写旧数据。

3.3.4 @Caching:缓存一致性编排器

@Caching(
evict = {
@CacheEvict(key = "'user:' + #oldEmail"),
...
},
put = {
@CachePut(key = "'user:' + #user.id"),
...
}
)

【工程评价】

你这里的写法已经是:

企业级缓存一致性模型示范

同时维护:

• ID 索引缓存
• 业务组合索引缓存

非常高级。

3.4 统一 Key 生成器(避免 Key 拼接混乱)
在生产项目里,最容易失控的就是 Key 拼接规则。
一旦大家各写各的:

"user:" + id
"USER_" + id
"user::" + id

Redis 会迅速变成“垃圾场”。

所以必须集中治理。

@Component("customKeyGenerator")
public class CustomKeyGenerator implements KeyGenerator {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(method.getName()).append(":");
for (Object param : params) {
sb.append(param).append(":");
}
return sb.toString();
}
}

使用方式:

@Cacheable(cacheNames = "userCache", keyGenerator = "customKeyGenerator")
public User getUserById(Long id) {
...
}

【工程价值】
在这里插入图片描述

3.5 Controller 层示例(完整链路)

@RestController
@RequestMapping("/users")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@GetMapping("/{id}")
public User get(@PathVariable Long id) {
return userService.getUserById(id);
}
@PutMapping
public User update(@RequestBody User user) {
return userService.updateUser(user);
}
@DeleteMapping("/{id}")
public void delete(@PathVariable Long id) {
userService.deleteUserById(id);
}
}

此时完整链路为:

HTTP → ControllerServiceCache → DB

这是标准 Spring Cache + Redis 架构模型。

3.6 监控与运维(生产必备)
缓存不监控 = 迟早出事故。

必须关注:
在这里插入图片描述

Redis 层面

info stats
info memory
info keyspace

关键字段:

keyspace_hits
keyspace_misses
used_memory
evicted_keys

Spring 层面(Micrometer)

management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
GET /actuator/metrics/cache.gets
GET /actuator/metrics/cache.puts
GET /actuator/metrics/cache.evictions

可直接对接:

• Prometheus
• Grafana

形成缓存命中率大盘。

3.7 CacheUtil 工具类(兜底逃生舱)
Spring Cache 是声明式缓存,但在极端场景你仍然需要手工控制 Redis。

@Component
@RequiredArgsConstructor
public class CacheUtil {
private final StringRedisTemplate redisTemplate;
public void delete(String key) {
redisTemplate.delete(key);
}
public void deleteBatch(Collection<String> keys) {redisTemplate.delete(keys);}public boolean exists(String key) {return Boolean.TRUE.equals(redisTemplate.hasKey(key));}}

典型使用场景:

• 运维紧急清缓存
• 批量修复脏数据
• 灰度期间定向清理

四、生产级缓存治理清单

如果你的项目满足下面 10 条,就可以说:

你的缓存架构已经“工程化”了。

在这里插入图片描述

⭐ = 高并发强烈建议

五、缓存三大经典事故 + 真实生产解法

缓存用不好,比不用还危险。
线上 90% 的 Redis 事故,都逃不开这三类:
在这里插入图片描述

5.1 缓存穿透(Cache Penetration)
场景:

用户请求 ID = -1 / 999999999
Redis 没有 → DB 也没有
每一次都直击数据库

如果被恶意刷接口:

Redis 完全失效,DB 直接崩。

解决方案一:不缓存 null + 参数校验

spring.cache.redis.cache-null-values: false
Controller 先做参数合法性校验:
if (id <= 0) {
throw new IllegalArgumentException("非法参数");
}

解决方案二:布隆过滤器(高并发必备)

请求 → BloomFilter → 不存在 → 直接拒绝
→ 可能存在 → Redis → DB

工程级方案:

• Redis + Redisson BloomFilter
• MySQL ID 同步初始化布隆

示意:

RBloomFilter<Long> bloomFilter = redissonClient.getBloomFilter("user:id:bf");bloomFilter.tryInit(10000000L, 0.01);

5.2 缓存击穿(Cache Breakdown)
场景:

某个超级热点 Key:user:1
10:00:00 过期
10:00:01 1 万个请求同时打 DB

DB 直接被冲死。

解决方案一:互斥锁

@Cacheable(...)
public User getUser(Long id) {
synchronized (this) {
return loadFromDB(id);
}
}

缺点:单机有效,多实例无效。

解决方案二:Redis 分布式锁(生产标准)

String lockKey = "lock:user:" + id;
if (redis.setIfAbsent(lockKey, "1", 5, TimeUnit.SECONDS)) {
// 查询 DB 并回填缓存
} else {
// 等待 + 重试
}

解决方案三:逻辑过期(高端方案)
缓存里存:

{
"data": {...},
"expireTime": "2026-01-22T10:00:00"
}

即使逻辑过期:

• 仍然返回旧数据
• 异步线程刷新缓存
• 用户无感知

这才是大厂方案。

5.3 缓存雪崩(Cache Avalanche)
场景:

1 万个 Key
TTL = 10 分钟
10 分钟同时失效

DB 死亡。

标准解法:TTL 随机化

long ttl = baseTtl + RandomUtil.randomLong(0, 300);

例如:

30 分钟 + 0~5 分钟随机
兜底方案:多级缓存
请求 → 本地 CaffeineRedis → DB

即使 Redis 掉了:

本地缓存还能抗 60 秒。

5.4 Redis 挂掉时你怎么办?
这是面试官最爱问的。

标准答案:

在这里插入图片描述

Spring:

@Cacheable(...)
@CircuitBreaker(name="redisBreaker", fallbackMethod="fallback")

六、缓存更新策略:你现在用的是否正确?

你当前方案是:

@CachePut
public User updateUser(User user)

这是 直接覆盖缓存型。

但大厂推荐:

更新数据库 → 删除缓存 → 让下次自然重建

原因:

• 防止脏数据
• 防止并发覆盖
• 逻辑简单

推荐改成:

@Transactional
public User updateUser(User user) {
userMapper.update(user);
redisTemplate.delete("userCache::" + user.getId());
return user;
}

七、Spring Cache 真实工作原理

一句话总结:

Spring Cache = AOP + CacheManager + CacheOperationSource

流程:

方法调用
↓
CacheInterceptor
↓
查 Redis
↓
有 → 返回
无 → 执行方法 → 放 Redis

八、总结:一份真正可复制的公司级缓存规范模板

1. 架构层面,你已经具备:

HTTP
↓
ControllerServiceSpring Cache 注解)
↓
RedisCacheManagerRedis

并且补齐了:

↘ 本地缓存(可选 Caffeine)
↘ 限流 / 熔断
↘ 降级兜底

这已经是完整的大厂缓存链路。

2. 设计层面,你已经具备:
在这里插入图片描述

3. 治理层面,你已经具备:
在这里插入图片描述
这点非常重要,因为:

能写缓存的人很多,
能治理缓存的人极少。

4. 事故层面,你已经完全免疫三大经典问题
在这里插入图片描述

你现在的缓存体系,是真正“抗事故”的。

http://www.jsqmd.com/news/448891/

相关文章:

  • MAUI 嵌入式 Web 架构实战(五) 构建完整的 Web Admin 管理后台
  • fastapi-guard fastapi 安全中间件
  • 第十九节:ArkTS状态管理V1@State、@Prop、@Link、@Watch核心讲解与示例演示 - 鸿蒙
  • YJV22电缆和普通YJV电缆区别是什么? - 非研科技
  • YJV电力电缆适合哪些低压供电场景 - 非研科技
  • 探索大语言模型在留学文书逻辑构建中的垂直化落地实践
  • 2026上海宠物内科好医生集合,爱宠健康保障,猫咪体检/宠物皮肤科/宠物骨科专家/宠物骨科,宠物内科医生哪家靠谱 - 品牌推荐师
  • AI与java的八股
  • 2026年2月砂石场设备回收,优质服务商排行榜来了,充电设备回收/干式变压器回收,砂石场设备回收厂家有哪些 - 品牌推荐师
  • DJYPVP2-22电缆比普通DJYPVP好在哪? - 非研科技
  • KVV控制电缆适合用在什么场景? - 非研科技
  • DJYPVP计算机电缆主要用在哪些设备上 - 非研科技
  • 服务器系统用什么好处?详解其核心优势与实际应用价值 - 实践
  • 酒店商旅平台有哪些?2026精选平台大盘点,高效差旅必备指南 - 匠言榜单
  • RVV电缆和RVVP屏蔽电缆到底有什么区别 - 非研科技
  • 沃尔玛购物卡回收如何查询实时报价?三步掌握行情动态 - 京顺回收
  • 上海有哪些做研发设计标准化服务商 - 冠顶工业设备
  • 上海宠物牙科2026攻略:服务周到医生不容错过,狗狗牙结石/宠物口腔科/狗狗洗牙/猫咪牙结石,宠物牙科医生推荐排行榜 - 品牌推荐师
  • 2026年链板提升机制造企业排行,选对品牌提升效率,斗式提升机/提升机链板/网带清洗机/清洗机网带,提升机实力厂家推荐榜 - 品牌推荐师
  • 读2025世界前沿技术发展报告05量子信息技术
  • 探索口碑与体验俱佳的OMO模式电商零售平台,企业适用的数字化运营/OMO模式电商零售,OMO模式电商零售系统排行 - 品牌推荐师
  • 2026化妆品加盟新机遇:口碑品牌引领风尚,化妆品加盟推荐悦容庄国际显著提升服务 - 品牌推荐师
  • 豆包推广公司联系方式 - 品牌2026
  • 从零学瑜伽,入门不迷路|武汉瑜伽入门教程,禧悦打造专属新手入门体系 - 冠顶工业设备
  • 2026评价好的鲜牛肉源头厂家推荐,排名靠前的有这些,新鲜牛肉/天祝白牦牛肉/白牦牛肉/牛肉,鲜牛肉供应厂家有哪些 - 品牌推荐师
  • 行业视角:2026年值得关注的粘钉一体机直销厂家,行业内有名的粘钉一体机排行榜宏海纸箱设备诚信务实提供高性价比服务 - 品牌推荐师
  • AI推广公司联系方式 - 品牌2026
  • 2026年青岛城阳区伸缩缝服务商综合实力解析与选购指南 - 2026年企业推荐榜
  • 聚焦异地患者就医难 北京正规三甲陪诊甄选指南:守嘉陪诊靠专业贴心圈粉 - 品牌排行榜单
  • 完整教程:基于集成学习的心肺听诊音自动分类系统设计与实现