一、项目概述
本实战教程将演示如何在 Spring Boot 项目中通过 Spring Cache 注解方式集成 Redis,实现高效的数据缓存功能。我们将创建一个简单的用户管理系统,展示各种缓存注解的使用方法。
【工程增强说明】
Spring Cache 本质上是一个缓存抽象层,它并不关心你底层用的是 Redis、EhCache 还是 Caffeine,它只定义了:
• CacheManager
• Cache
• CacheOperation
真正决定缓存行为的是你配置的 CacheManager 实现,而我们这里选择的是:
java
RedisCacheManager
这意味着你的缓存具备:

本项目适合:
• 中大型 Spring Boot 后端服务
• 分布式系统缓存标准模板
• 公司级缓存规范示例
【生产定位】
这不是"Hello Redis",而是:
可以直接拿去当公司缓存架构样板的工程模板。
二、环境准备
2.1 依赖配置
java
<!-- 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.0
http://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>
【生产补充:这几项依赖的真实职责】

【版本选择说明】
你用的是:
java
Spring Boot 3.1.0 + Java 17
这意味着:
• Spring Framework 6.x
• Jakarta 命名空间
• 默认使用 Lettuce 客户端
• Redis 7 完美适配
是 当前主流生产版本组合,非常优秀。
2.2 Redis 配置
java
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
【生产级参数解读】

【生产建议版】
生产环境更推荐:
java
spring:
cache:
redis:
time-to-live: 1800000
cache-null-values: false
key-prefix: "PROD_CACHE:"
三、核心代码实现
这一部分是整篇文章的灵魂。
Spring Cache 用得好不好,80% 都取决于这里的设计是否"工程化"。
3.1 缓存配置类
java
@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:为什么必须统一序列化?】
如果你不显式指定:
java
.serializeValuesWith(...)
Spring Boot 3 默认会使用:
java
JdkSerializationRedisSerializer
问题是:
• Redis 里是二进制,看不懂
• Java 类变动就反序列化失败
• 跨语言无法使用
而你现在用的是:
java
GenericJackson2JsonRedisSerializer
这是生产最优解之一:

【生产补充 2:CacheName 的设计就是"缓存分区"】
你现在的:
java
userCache
productCache
shortCache
本质等价于:

这就是缓存层的领域模型分区设计。
【高级建议:TTL 加随机,防雪崩】
生产建议:
java
Duration base = Duration.ofMinutes(10);
long random = ThreadLocalRandom.current().nextLong(60);
.entryTtl(base.plusSeconds(random))
避免大量 Key 同时失效。
3.2 实体类
java
@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:读缓存标准模型
java
@Cacheable(key = "'user:' + #id", unless = "#result == null")
public User getUserById(Long id) {
log.info("从数据库查询用户: {}", id);
simulateSlowService();
return userDatabase.get(id);
}
【缓存模型解释】
这是标准的:
java
Cache Aside Pattern
流程:
- 先查缓存
- 缓存没有 → 查 DB
- 放入缓存
- 返回结果
这是互联网最经典缓存模式。
【生产级 Key 设计规范】
你现在的 Key:
java
CACHE:userCache::user:123
完整结构是:
java
{前缀}:{CacheName}::{业务Key}
这是非常优秀的企业级规范。
3.3.2 @CachePut:更新必写缓存
java
@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:缓存失效治理
java
@CacheEvict(key = "'user:' + #id")
public void deleteUserById(Long id) {
userDatabase.remove(id);
}
【生产增强:双删策略】
- 删除 DB
- 删除缓存
- 延迟 500ms 再删一次
防止并发回写旧数据。
3.3.4 @Caching:缓存一致性编排器
java
@Caching(
evict = {
@CacheEvict(key = "'user:' + #oldEmail"),
...
},
put = {
@CachePut(key = "'user:' + #user.id"),
...
}
)
【工程评价】
你这里的写法已经是:
企业级缓存一致性模型示范
同时维护:
• ID 索引缓存
• 业务组合索引缓存
非常高级。
3.4 统一 Key 生成器(避免 Key 拼接混乱)
在生产项目里,最容易失控的就是 Key 拼接规则。
一旦大家各写各的:
java
"user:" + id
"USER_" + id
"user::" + id
Redis 会迅速变成"垃圾场"。
所以必须集中治理。
java
@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();
}
}
使用方式:
java
@Cacheable(cacheNames = "userCache", keyGenerator = "customKeyGenerator")
public User getUserById(Long id) {
...
}
【工程价值】

3.5 Controller 层示例(完整链路)
java
@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);
}
}
此时完整链路为:
java
HTTP → Controller → Service → Cache → DB
这是标准 Spring Cache + Redis 架构模型。
3.6 监控与运维(生产必备)
缓存不监控 = 迟早出事故。
必须关注:

Redis 层面
java
info stats
info memory
info keyspace
关键字段:
java
keyspace_hits
keyspace_misses
used_memory
evicted_keys
Spring 层面(Micrometer)
java
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。
java
@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)
场景:
java
用户请求 ID = -1 / 999999999
Redis 没有 → DB 也没有
每一次都直击数据库
如果被恶意刷接口:
java
Redis 完全失效,DB 直接崩。
解决方案一:不缓存 null + 参数校验
java
spring.cache.redis.cache-null-values: false
Controller 先做参数合法性校验:
if (id <= 0) {
throw new IllegalArgumentException("非法参数");
}
解决方案二:布隆过滤器(高并发必备)
java
请求 → BloomFilter → 不存在 → 直接拒绝
→ 可能存在 → Redis → DB
工程级方案:
• Redis + Redisson BloomFilter
• MySQL ID 同步初始化布隆
示意:
java
RBloomFilter<Long> bloomFilter = redissonClient.getBloomFilter("user:id:bf");
bloomFilter.tryInit(10000000L, 0.01);
5.2 缓存击穿(Cache Breakdown)
场景:
java
某个超级热点 Key:user:1
10:00:00 过期
10:00:01 1 万个请求同时打 DB
DB 直接被冲死。
解决方案一:互斥锁
java
@Cacheable(...)
public User getUser(Long id) {
synchronized (this) {
return loadFromDB(id);
}
}
缺点:单机有效,多实例无效。
解决方案二:Redis 分布式锁(生产标准)
java
String lockKey = "lock:user:" + id;
if (redis.setIfAbsent(lockKey, "1", 5, TimeUnit.SECONDS)) {
// 查询 DB 并回填缓存
} else {
// 等待 + 重试
}
解决方案三:逻辑过期(高端方案)
缓存里存:
java
{
"data": {...},
"expireTime": "2026-01-22T10:00:00"
}
即使逻辑过期:
• 仍然返回旧数据
• 异步线程刷新缓存
• 用户无感知
这才是大厂方案。
5.3 缓存雪崩(Cache Avalanche)
场景:
java
1 万个 Key
TTL = 10 分钟
10 分钟同时失效
DB 死亡。
标准解法:TTL 随机化
java
long ttl = baseTtl + RandomUtil.randomLong(0, 300);
例如:
java
30 分钟 + 0~5 分钟随机
兜底方案:多级缓存
请求 → 本地 Caffeine → Redis → DB
即使 Redis 掉了:
本地缓存还能抗 60 秒。
5.4 Redis 挂掉时你怎么办?
这是面试官最爱问的。
标准答案:

Spring:
java
@Cacheable(...)
@CircuitBreaker(name="redisBreaker", fallbackMethod="fallback")
六、缓存更新策略:你现在用的是否正确?
你当前方案是:
java
@CachePut
public User updateUser(User user)
这是 直接覆盖缓存型。
但大厂推荐:
java
更新数据库 → 删除缓存 → 让下次自然重建
原因:
• 防止脏数据
• 防止并发覆盖
• 逻辑简单
推荐改成:
java
@Transactional
public User updateUser(User user) {
userMapper.update(user);
redisTemplate.delete("userCache::" + user.getId());
return user;
}
七、Spring Cache 真实工作原理
一句话总结:
Spring Cache = AOP + CacheManager + CacheOperationSource
流程:
java
方法调用
↓
CacheInterceptor
↓
查 Redis
↓
有 → 返回
无 → 执行方法 → 放 Redis
八、总结:一份真正可复制的公司级缓存规范模板
1. 架构层面,你已经具备:
java
HTTP
↓
Controller
↓
Service(Spring Cache 注解)
↓
RedisCacheManager
↓
Redis
并且补齐了:
java
↘ 本地缓存(可选 Caffeine)
↘ 限流 / 熔断
↘ 降级兜底
这已经是完整的大厂缓存链路。
2. 设计层面,你已经具备:

3. 治理层面,你已经具备:

这点非常重要,因为:
能写缓存的人很多,
能治理缓存的人极少。
4. 事故层面,你已经完全免疫三大经典问题

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