SpringBoot4 + Redis8 整合开发实践指南
作者:java1234_小锋
网上很多都是老旧版本的整合开发,锋哥整理了下最新版本整合开发的注意点,以及新特性用法。
一、为什么选这套组合
Spring Boot 4 在 2025 年底正式发布,底层是 Spring Framework 7,默认要求 Java 17,对 Jackson 3、Jakarta EE 11 做了统一升级。日常开发里,你能明显感受到两点变化:启动配置更模块化,以及 空安全注解(JSpecify) 让 IDE 提示更准。
Redis 8 则在性能和新命令上持续发力。配合 Spring Data Redis 4.1,以前要自己拼 RedisMessageListenerContainer 的 Pub/Sub,现在可以像写 @KafkaListener 一样写 @RedisListener;Redis 8.4 新增的 Compare-and-Set、DIGEST 等命令,Spring 侧也已经跟上了。
一句话总结:新项目用 Spring Boot 4 + Redis 8,开发体验更顺,也不用背那么多样板代码。
二、整体架构长什么样
一个典型的 Spring Boot 4 应用接入 Redis 8,可以分成三层来理解:

| 层级 | 职责 | 常用组件 |
|---|---|---|
| 应用层 | 处理业务请求、发消息、加缓存 | Controller、Service、@Cacheable、@RedisListener |
| 中间层 | 屏蔽 Redis 协议细节 | RedisTemplate、RedisCacheManager、Lettuce 连接池 |
| 存储层 | 真正存数据、跑命令 | Redis 8 的 String/Hash、Pub/Sub、Stream、JSON 模块 |
业务代码尽量只碰应用层和 Spring 提供的 API,别在 Service 里直接拼 Redis 命令字符串——后期换客户端、做单元测试都会轻松很多。
三、项目快速搭建
3.1 核心依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.1.0</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
</dependencies>3.2 基础配置
spring:
data:
redis:
host: 127.0.0.1
port: 6379
password:
lettuce:
pool:
max-active: 16
max-idle: 8
min-idle: 2
max-wait: 3000ms
cache:
type: redis
redis:
time-to-live: 30m
cache-null-values: false3.3 Redis 连接配置类
@Configuration
@EnableCaching
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJacksonJsonRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(new GenericJacksonJsonRedisSerializer());
template.afterPropertiesSet();
return template;
}
}到这里,一个能跑起来的基础整合就完成了。下面进入本文重点——新特性怎么用。
四、新特性实战 Demo
4.1 注解驱动的 Redis 消息监听
以前的做法:手动创建 RedisMessageListenerContainer,注册 MessageListener,代码散在好几个类里。
现在的做法:加 @EnableRedisListeners,在方法上标 @RedisListener,跟 Kafka 那套几乎一样。

配置类:
@Configuration
@EnableRedisListeners
public class RedisListenerConfig {
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer(
RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
return container;
}
}消息发送方:
@Service
public class OrderNotifyService {
private final RedisMessageSendingTemplate<String, String> sendingTemplate;
public OrderNotifyService(RedisMessageSendingTemplate<String, String> sendingTemplate) {
this.sendingTemplate = sendingTemplate;
}
public void notifyOrderPaid(Long orderId) {
String payload = "{\"orderId\":" + orderId + ",\"status\":\"PAID\"}";
sendingTemplate.convertAndSend("order-notify", payload);
}
}消息接收方:
@Component
public class OrderNotifyListener {
private static final Logger log = LoggerFactory.getLogger(OrderNotifyListener.class);
@RedisListener(topic = "order-notify")
public void onOrderPaid(String message) {
log.info("收到订单通知: {}", message);
// 这里写你的业务逻辑,比如更新本地状态、发站内信等
}
}小提示:如果消息体是 JSON,可以在 @RedisListener(consumes = "application/json") 里声明类型,框架会自动选对应的转换器。
4.2 Compare-and-Set:乐观锁不用写 Lua 了
分布式场景里经常遇到这种需求:「只有当 key 当前值等于 A 时,才改成 B」。以前很多人写 Lua 脚本来保证原子性。
Redis 8.4 提供了 Compare-and-Set(CAS)和 Compare-and-Delete(CAD),Spring Data Redis 4.1 在 RedisTemplate 层已经封装好了。
场景示例:防止优惠券被重复领取
@Service
public class CouponService {
private final StringRedisTemplate stringRedisTemplate;
public CouponService(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
/**
* 只有券状态为 AVAILABLE 时,才改成 CLAIMED
*/
public boolean claimCoupon(String couponId, String userId) {
String key = "coupon:" + couponId;
Boolean success = stringRedisTemplate.opsForValue()
.setIfPresent(key, "CLAIMED:" + userId,
Duration.ofHours(24));
return Boolean.TRUE.equals(success);
}
/**
* 只有值匹配时才删除(用于 token 失效场景)
*/
public boolean invalidateToken(String token) {
String key = "token:" + token;
return Boolean.TRUE.equals(
stringRedisTemplate.delete(key, token));
}
}CAS 适合读多写少、冲突概率不高的场景。如果同一 key 并发极高,还是建议上 Redisson 分布式锁或数据库乐观锁字段。
4.3 DIGEST 命令:更快的哈希计算
Redis 8 新增的 DIGEST 命令,用 XXH3 算法算哈希,比自己在应用层算 MD5/SHA 再存进去更省事,也更适合做大文件或长字符串的指纹比对。
@Service
public class FileDigestService {
private final RedisTemplate<String, String> redisTemplate;
public FileDigestService(RedisTemplate<String, String> redisTemplate) {
this.redisTemplate = redisTemplate;
}
public String computeDigest(String content) {
// 调用 Redis 8 DIGEST 命令,服务端计算 XXH3 哈希
return redisTemplate.execute((RedisCallback<String>) connection ->
connection.digest(content.getBytes(StandardCharsets.UTF_8)));
}
public boolean isDuplicate(String content) {
String digest = computeDigest(content);
String key = "file:digest:" + digest;
Boolean isNew = redisTemplate.opsForValue()
.setIfAbsent(key, "1", Duration.ofDays(7));
return !Boolean.TRUE.equals(isNew); // true 表示重复文件
}
}典型用途:上传去重、缓存键生成、数据一致性抽检。
4.4 Duration 过期 API:告别 TimeUnit 混乱
Spring Data Redis 4.1 开始,推荐用 Duration 和 Expiration 替代 TimeUnit 参数。语义更清晰,也不容易把「秒」和「毫秒」搞反。
// 旧写法(已标记过时)
// redisTemplate.expire("user:1001", 30, TimeUnit.MINUTES);
// 新写法(推荐)
redisTemplate.expire("user:1001", Duration.ofMinutes(30));
// 带过期条件的 SET
redisTemplate.opsForValue().set("session:abc", userInfo,
Expiration.from(Duration.ofHours(2)));团队里如果有 Code Review 规范,可以直接约定:新代码一律用 Duration,老代码迁移时顺手改。
4.5 一键清空缓存:resetCaches
运维或测试环境经常需要「把所有缓存清掉」。以前要么 FLUSHDB(太狠),要么自己维护 key 列表。
Spring Data Redis 4.1 给 CacheManager 加了 resetCaches(),会按缓存区域批量清理,比全库 flush 安全。
@RestController
@RequestMapping("/admin/cache")
public class CacheAdminController {
private final CacheManager cacheManager;
public CacheAdminController(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
@PostMapping("/reset")
public String resetAllCaches() {
if (cacheManager instanceof RedisCacheManager redisCacheManager) {
redisCacheManager.resetCaches();
return "缓存已重置";
}
return "当前 CacheManager 不支持 resetCaches";
}
}注意:生产环境要给这个接口加权限控制,别裸奔在线上。
五、缓存使用最佳实践

结合上图,几条实战经验:
1. 合理设置 TTL
缓存不是越久越好。热点数据 5~30 分钟,配置类数据 1~24 小时,按业务容忍的「脏读时间」来定。
2. 注意缓存穿透
查询不存在的数据时,别把 null 也缓存了(除非你能接受)。配置里 cache-null-values: false 是第一步,还可以对空结果缓存一个短 TTL 的占位值。
3. 更新策略选对
| 场景 | 推荐做法 |
|---|---|
| 读多写少 | @Cacheable + 过期自动失效 |
| 写后立即读 | @CachePut 或先更新 DB 再删缓存 |
| 数据一致性要求高 | 先更新 DB,再 @CacheEvict 删缓存 |
4. 示例:商品详情缓存
@Service
public class ProductService {
@Cacheable(value = "product", key = "#id")
public Product getById(Long id) {
return productMapper.selectById(id);
}
@CacheEvict(value = "product", key = "#product.id")
public void update(Product product) {
productMapper.updateById(product);
}
}六、生产环境配置建议
不需要一上来就搞集群,但下面几条建议尽早落地:
spring:
data:
redis:
timeout: 3s
connect-timeout: 3s
lettuce:
pool:
max-active: 32
max-idle: 16
min-idle: 4
shutdown-timeout: 200ms连接池:Lettuce 默认共享连接,高并发场景务必开 commons-pool2,按 QPS 调整 max-active。
序列化:生产环境统一用 JSON 序列化(Jackson),方便排查问题时用 redis-cli 直接看内容。
监控:Spring Boot Actuator 配合 spring-boot-starter-data-redis 的健康检查,能及时发现 Redis 连不上的情况。
Key 规范:建议统一前缀,比如 app:module:biz:id,避免多服务共用一个 Redis 实例时互相踩 key。
七、最后锋哥小结下哈
Spring Boot 4 和 Redis 8 凑在一起,并不是「版本号 +1」那么简单。实际开发中值得优先用上的几点:
@RedisListener—— Pub/Sub 监听声明式写法,代码量明显减少- CAS / CAD —— 乐观锁、token 失效等场景,不用再手写 Lua
- DIGEST —— 哈希计算交给 Redis,应用层更轻
- Duration API —— 过期时间写法统一,减少低级 bug
- resetCaches —— 缓存清理更可控,告别粗暴
FLUSHDB
建议新项目直接以 Spring Boot 4.1 + Spring Data Redis 4.1 + Redis 8.4 作为基线。老项目如果还在 Boot 3.x,可以先把 Redis 客户端升上去,再规划 Boot 4 迁移——两条线并行,风险更小。
到此这篇关于SpringBoot4 + Redis8 整合开发 最佳实践的文章就介绍到这了,更多相关SpringBoot4 Redis8开发内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
