
magic-spring-boot-starter-redis 提供了两种优雅的 Redis 缓存使用方式,兼顾灵活性和便捷性:
- 编程式缓存:基于 Spring Data Redis 框架的 RedisTemplate 操作模板
- 声明式缓存:基于 Spring Cache 框架的
@Cacheable注解
关于 SpringCache , 不太了解的同学,可以先阅读:品味 SpringCache 设计之美 (opens new window)
文章视频地址:https://www.bilibili.com/video/BV1ZK411e751
# 1 编程式缓存 Spring Data Redis
技术实现:基于 Spring Data Redis 的 RedisTemplate 操作模板
适用场景:需要精细控制缓存逻辑的复杂业务场景
核心优势:
- 直接操作 Redis 命令,灵活性高
- 支持原子性操作和复杂数据结构
代码示例:
@Service
public class ProductService {
@Autowired
private RedisTemplate<String, Product> redisTemplate;
public Product getProduct(String sku) {
// 先查缓存
Product product = redisTemplate.opsForValue().get("product:" + sku);
if (product == null) {
// 缓存未命中时查DB
product = productRepository.findBySku(sku);
// 写入缓存并设置TTL
redisTemplate.opsForValue().set(
"product:" + sku,
product,
Duration.ofMinutes(30));
}
return product;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 2 声明式缓存 SpringCache
技术实现 :基于 Spring Cache 抽象 + @Cacheable 等注解
适用场景 :常规缓存需求,追求代码简洁性
核心优势 :
- 无侵入式缓存,业务代码零污染
- 支持条件缓存(unless/condition)
示例代码 :
// 创建菜单并清理指定权限的缓存
@CacheEvict(
value = RedisKeyConstants.PERMISSION_MENU_ID_LIST,
key = "#createReqVO.permission",
condition = "#createReqVO.permission != null" // 仅当permission非空时执行缓存清理
)
public Long createMenu(MenuSaveVO createReqVO) {
// 数据转换与初始化
MenuDO menu = BeanUtils.toBean(createReqVO, MenuDO.class);
initMenuProperty(menu);
// 持久化操作
menuMapper.insert(menu);
return menu.getId();
}
// 更新菜单(全量清理缓存)
@CacheEvict(
value = RedisKeyConstants.PERMISSION_MENU_ID_LIST,
allEntries = true // 强制清空整个缓存区域
)
public void updateMenu(MenuSaveVO updateReqVO) {
// 数据转换与初始化
MenuDO updateObj = BeanUtils.toBean(updateReqVO, MenuDO.class);
initMenuProperty(updateObj);
// 持久化操作
menuMapper.updateById(updateObj);
}
// 根据权限获取菜单ID列表(带缓存读取)
@Cacheable(
value = RedisKeyConstants.PERMISSION_MENU_ID_LIST,
key = "#permission" // 以permission参数作为缓存键
)
public List<Long> getMenuIdListByPermissionFromCache(String permission) {
// 缓存未命中时的数据加载逻辑
List<MenuDO> menus = menuMapper.selectListByPermission(permission);
return convertList(menus, MenuDO::getId);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
创建和修改菜单时会删除所有的菜单缓存 (使用注解 CacheEvict ),而根据权限 permission 查询时,会缓存该权限对应的所有的菜单 ID 列表 (使用注解 Cacheable )。
# 3 基本原理
# 01 Spring Data Redis
Spring Data Redis 是 Spring Data 项目的一部分,它为 Redis 提供了 方便、统一的访问方式,封装了对 Redis 的操作。
但 Spring Data Redis 底层的连接通信实现是通过 Redis 客户端来完成的,它本身不直接实现 Redis 协议,而是通过整合已有的 Redis Java 客户端。
目前支持的主要客户端有三个:
| 特性 / 客户端 | Jedis | Lettuce | Redisson |
|---|---|---|---|
| 类型 | 原始客户端 | 原始客户端 | 高级封装客户端 |
| IO 模型 | BIO(阻塞 IO) | NIO(基于 Netty) | NIO(基于 Netty) |
| 连接复用 | 每线程独立连接(需连接池) | 支持共享连接(多线程复用) | 支持共享连接 |
| 异步支持 | ❌ | ✅(支持异步 / 响应式) | ✅(支持异步) |
| 分布式锁 | ❌(需手动实现) | ❌(需手动实现) | ✅(内置支持) |
| 限流 / 信号量 / 队列 | ❌ | ❌ | ✅(全面支持) |
| 事务支持 | ✅ | ✅ | ✅ |
| Lua 脚本 | ✅ | ✅ | ✅ |
| Pub/Sub | ✅ | ✅ | ✅ |
| 连接池机制 | 必须使用(如 JedisPool) | 可选(线程安全,无需池) | 内部管理 |
| 学习成本 | 低 | 中 | 中高 |
| Spring Boot 默认支持 | ❌(需配置) | ✅(默认客户端) | ❌(需手动集成) |
| 适合场景 | 小型、简单应用 | 中大型系统、响应式、高并发 | 高并发 + 分布式功能场景 |
默认情况下,项目中添加依赖 , 依赖的客户端是:Lettuce 。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2
3
4
但假如我们想使用 Redisson 的高级功能 (分布式锁、消息队列、限流) ,那么需要添加 Reddisson 的 Spring Data Redis 依赖。
<!-- Redisson 启动器,简化与 Spring Boot 的集成 -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
</dependency>
<!-- Redisson 对 Spring Data Redis 的整合,版本号中的 27 对应 Spring Data 2.7.x -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-data-27</artifactId>
</dependency>
2
3
4
5
6
7
8
9
10
11
接下来,配置 RedisTemplate Bean,使用 JSON 序列化方式 。
/**
* 创建 RedisTemplate Bean,使用 JSON 序列化方式
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
// 创建 RedisTemplate 对象
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 设置 RedisConnection 工厂。😈 它就是实现多种 Java Redis 客户端接入的秘密工厂。感兴趣的胖友,可以自己去撸下。
template.setConnectionFactory(factory);
// 使用 String 序列化方式,序列化 KEY 。
template.setKeySerializer(RedisSerializer.string());
template.setHashKeySerializer(RedisSerializer.string());
// 使用 JSON 序列化方式(库是 Jackson ),序列化 VALUE 。
template.setValueSerializer(buildRedisSerializer());
template.setHashValueSerializer(buildRedisSerializer());
return template;
}
public static RedisSerializer<?> buildRedisSerializer() {
RedisSerializer<Object> json = RedisSerializer.json();
// 解决 LocalDateTime 的序列化
ObjectMapper objectMapper = (ObjectMapper) ReflectUtil.getFieldValue(json, "mapper");
objectMapper.registerModules(new JavaTimeModule());
return json;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
通过上面的配置,我们可以使用 Spring Data Redis 的基础功能 ,同时也可以使用 Redisson 的高级功能。
下面是使用分布式锁的一个例子,我们可以天然使用 Redisson 的内置客户端 RedissonClient 。
@RestController
@Slf4j
public class DefaultController {
@Autowired
private RedissonClient redissonClient;
@RequestMapping(value = {"/test"})
@PermitAll
public CommonResult<Boolean> test(HttpServletRequest request) {
// 打印查询参数
Lock lock = redissonClient.getLock("testLock");
try {
lock.lock();
// 省略代码
}finally {
lock.unlock();
}
return CommonResult.success(true);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 02 Spring Cache
1、添加依赖
要实现 Spring Cache 的功能,首先添加 Spring Cache 的依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId> <!-- 实现对 Caches 的自动化配置 -->
</dependency>
2
3
4
2、配置
在 application.yaml 配置文件中,通过 spring.redis 配置项,设置 Redis 的配置。如下图所示:

3、配置 CacheManager
最后,需要用于通过 RedisCacheManager 和 RedisCacheConfiguration 来自定义 Spring Cache 缓存的行为。
- RedisCacheConfiguration 定义缓存行为

- RedisCacheManager 缓存管理器
Spring Cache 默认使用 spring.cache.redis.time-to-live 配置项,设置缓存的过期时间,项目默认为 1 小时。
如果你想自定义过期时间,可以在 @Cacheable 注解中的 cacheNames 属性中,添加 #{过期时间} 后缀,单位是秒。如下图所示:

如下图,TimeoutRedisCacheManager 缓存管理器内部创建缓存对象时,会通过 cacheName 属性解析出过期时间参数,并重新设置。

