Redis Java 集成到 Spring Boot:从单机到集群的使用样例
在 Java 项目里使用 Redis,除了直接使用 Jedis,还可以把 Redis 集成到 Spring Boot 中,通过 Spring Data Redis 提供的模板类来操作。本文按照文档顺序,整理 Spring Boot 连接 Redis 单机、编写 Controller 测试接口、操作常见 Redis 数据结构,以及连接 Redis 集群的完整流程。
本文示例主要使用 StringRedisTemplate。它适合操作 key 和 value 都是字符串的 Redis 数据,接口风格和原始 Redis 命令略有不同,但整体思路是一致的。
1. 使用 Spring Boot 连接 Redis 单机
1.1 创建项目
创建 Spring Boot 项目时,依赖选择中勾选 NoSQL 分类下的:
text
Spring Data Redis
为了方便写接口测试 Redis 操作,也建议同时勾选 Web 分类下的:
text
Spring Web
这样项目创建完成后,就可以通过 Controller 暴露测试接口,在浏览器或接口测试工具里触发 Redis 操作。
1.2 配置 Redis 服务地址
在 application.yml 中配置 Redis 的主机和端口:
yaml
spring:
redis:
host: 127.0.0.1
port: 8888
这里的 127.0.0.1:8888 表示 Java 程序访问本地 8888 端口。如果 Redis 本身就在本机运行,并且使用默认端口,可以改成:
yaml
spring:
redis:
host: 127.0.0.1
port: 6379
如果 Redis 安装在云服务器上,也可以通过端口转发把远程 Redis 的 6379 映射到本地 8888,这样 Spring Boot 项目仍然访问 127.0.0.1:8888。
2. 创建 Controller
文档里的示例只是为了演示 Redis 的基本操作,所以没有做 Service、Mapper 等分层,直接创建一个简单的 Controller。
java
@RestController
public class MyController {
@Autowired
private StringRedisTemplate redisTemplate;
}
这里注入的是 StringRedisTemplate。它是 Spring Data Redis 提供的模板对象,里面封装了很多 Redis 操作方法。
常见操作入口如下:
text
opsForValue() -> 操作 String
opsForList() -> 操作 List
opsForHash() -> 操作 Hash
opsForSet() -> 操作 Set
opsForZSet() -> 操作 ZSet
也就是说,在 Spring Boot 里不再直接调用 set、lpush、hset 这类命令,而是先通过 opsForXxx() 拿到对应数据结构的操作对象,再调用具体方法。
3. 使用 String
String 是 Redis 中最基础的数据结构。使用 StringRedisTemplate 操作 String 时,需要通过 opsForValue()。
java
@GetMapping("/testString")
@ResponseBody
public String testString() {
redisTemplate.opsForValue().set("key", "value");
String value = redisTemplate.opsForValue().get("key");
System.out.println(value);
redisTemplate.delete("key");
return "OK";
}
这段代码的执行流程是:
- 向 Redis 写入
key -> value。 - 再根据
key读取 value。 - 把读取到的结果打印到控制台。
- 删除这个测试 key。
- 给浏览器或接口测试工具返回
OK。
它对应的 Redis 命令大致可以理解为:
redis
SET key value
GET key
DEL key
4. 使用 List
List 可以理解为 Redis 中的列表结构,支持从左侧或右侧插入元素,也支持按下标范围读取元素。使用 StringRedisTemplate 操作 List 时,通过 opsForList()。
java
@GetMapping("/testList")
@ResponseBody
public String testList() {
redisTemplate.opsForList().leftPush("key", "a");
redisTemplate.opsForList().leftPushAll("key", "b", "c", "d");
List<String> values = redisTemplate.opsForList().range("key", 1, 2);
System.out.println(values);
redisTemplate.delete("key");
return "OK";
}
这里用到的几个方法含义是:
text
leftPush() -> 从列表左侧插入一个元素
leftPushAll() -> 从列表左侧批量插入多个元素
range() -> 按下标范围获取列表元素
range("key", 1, 2) 表示获取下标从 1 到 2 的元素,区间是闭区间。
因为示例使用的是 leftPush,每次都从左侧插入,所以元素最终顺序和插入参数顺序不一定完全一样。学习 List 时,要特别注意"左侧插入"和"右侧插入"对顺序的影响。
5. 使用 Hash
Hash 适合保存对象结构,例如一个用户对象可以保存多个字段:name、age、email 等。使用 StringRedisTemplate 操作 Hash 时,通过 opsForHash()。
java
@GetMapping("/testHashmap")
@ResponseBody
public String testHashmap() {
redisTemplate.opsForHash().put("key", "name", "zhangsan");
String value = (String) redisTemplate.opsForHash().get("key", "name");
System.out.println(value);
redisTemplate.opsForHash().delete("key", "name");
boolean ok = redisTemplate.opsForHash().hasKey("key", "name");
System.out.println(ok);
redisTemplate.delete("key");
return "OK";
}
这段代码主要演示了四个动作:
text
put() -> 写入 hash 字段
get() -> 读取 hash 字段
delete() -> 删除 hash 字段
hasKey() -> 判断 hash 字段是否存在
对应到 Redis 命令,大致可以理解为:
redis
HSET key name zhangsan
HGET key name
HDEL key name
HEXISTS key name
需要注意,opsForHash().get() 返回值类型是 Object,如果确定里面存的是字符串,可以像示例中一样强制转换为 String。
6. 使用 Set
Set 是无序、不重复集合。它适合表示"某个元素是否存在于集合中"这类问题。使用 StringRedisTemplate 操作 Set 时,通过 opsForSet()。
java
@GetMapping("/testSet")
@ResponseBody
public String testSet() {
redisTemplate.opsForSet().add("key", "aaa", "bbb", "ccc");
boolean ok = redisTemplate.opsForSet().isMember("key", "aaa");
System.out.println(ok);
redisTemplate.opsForSet().remove("key", "aaa");
long n = redisTemplate.opsForSet().size("key");
System.out.println(n);
redisTemplate.delete("key");
return "OK";
}
这里用到的几个方法含义是:
text
add() -> 添加集合元素
isMember() -> 判断元素是否属于集合
remove() -> 删除集合元素
size() -> 获取集合元素数量
对应到 Redis 命令,大致是:
redis
SADD key aaa bbb ccc
SISMEMBER key aaa
SREM key aaa
SCARD key
Set 的元素没有固定顺序,因此如果后续打印集合内容,不要依赖它的输出顺序。
7. 使用 ZSet
ZSet 也叫有序集合。它和 Set 一样,member 不允许重复,但每个 member 都会关联一个 score,Redis 会按照 score 进行排序。使用 StringRedisTemplate 操作 ZSet 时,通过 opsForZSet()。
java
@GetMapping("/testZSet")
@ResponseBody
public String testZSet() {
redisTemplate.opsForZSet().add("key", "吕布", 100);
redisTemplate.opsForZSet().add("key", "赵云", 98);
redisTemplate.opsForZSet().add("key", "典韦", 95);
Set<String> values = redisTemplate.opsForZSet().range("key", 0, 2);
System.out.println(values);
long n = redisTemplate.opsForZSet().count("key", 95, 100);
System.out.println(n);
redisTemplate.delete("key");
return "OK";
}
这段代码主要演示:
text
add() -> 添加 member 和 score
range() -> 按排名范围获取 member
count() -> 统计指定 score 区间内的 member 数量
默认情况下,range("key", 0, 2) 会按照 score 从小到大返回指定范围内的元素。示例中 典韦 的分数是 95,赵云 是 98,吕布 是 100。
count("key", 95, 100) 统计分数在 95 到 100 之间的元素数量,区间包含两端。
8. 执行结果
运行 Spring Boot 程序后,分别访问上面的接口:
text
/testString
/testList
/testHashmap
/testSet
/testZSet
每个接口都会向 Redis 写入测试数据,读取或判断结果,把结果打印到服务器控制台,最后删除测试 key,并返回:
text
OK
如果浏览器页面返回 OK,说明接口执行成功。具体 Redis 操作的输出结果,需要在 Spring Boot 启动窗口或控制台中查看。
9. 使用 Spring Boot 连接 Redis 集群
前面的配置连接的是 Redis 单机。如果要连接 Redis Cluster,需要把配置改成集群节点列表。
yaml
spring:
redis:
cluster:
nodes:
- 172.30.0.101:6379
- 172.30.0.102:6379
- 172.30.0.103:6379
- 172.30.0.104:6379
- 172.30.0.105:6379
- 172.30.0.106:6379
- 172.30.0.107:6379
- 172.30.0.108:6379
- 172.30.0.109:6379
lettuce:
cluster:
refresh:
adaptive: true
period: 2000
这里配置了多个 Redis 集群节点地址。Spring Boot 会根据这些节点信息连接 Redis Cluster。
下面的 Lettuce 配置用于自动刷新集群拓扑结构:
yaml
lettuce:
cluster:
refresh:
adaptive: true
period: 2000
它的作用是:当集群中有节点宕机、恢复,或者有新节点加入时,客户端能够感知集群结构的变化。这样应用程序不需要一直使用启动时拿到的旧拓扑信息。
改完配置后,上面 Controller 中的代码不需要调整,仍然可以继续使用 StringRedisTemplate 操作 Redis。
10. 集群访问注意事项
文档中的集群 IP 类似:
text
172.30.0.101
172.30.0.102
172.30.0.103
这些通常是 Docker 容器内部 IP。在 Windows 主机上,Java 程序可能无法直接访问这些容器 IP。
因此,如果 Redis 集群运行在 Linux 的 Docker 环境中,更稳妥的方式是把 Spring Boot 项目打成 jar 包,上传到 Linux 环境中运行:
bash
java -jar app.jar
这样 Spring Boot 程序和 Redis 集群处于同一个网络环境中,访问这些容器 IP 才更容易成功。
11. 小结
Spring Boot 2 系列默认使用 Lettuce 作为 Redis 客户端,它和 Jedis 的使用方式有一定差异。
Jedis 的方法名通常和 Redis 原生命令非常接近,例如 set、get、lpush、hset 等。而集成到 Spring Boot 之后,更常见的写法是通过 StringRedisTemplate:
text
opsForValue()
opsForList()
opsForHash()
opsForSet()
opsForZSet()
虽然接口形式不同,但底层操作的 Redis 数据结构仍然是一样的。只要熟悉 Redis 的基本数据类型和常见命令,就能比较容易地通过方法名理解 Spring Data Redis 的用法。
学习时可以按这个顺序练习:
- 先配置单机 Redis 地址,确认 Spring Boot 能连上 Redis。
- 再通过 Controller 分别练习 String、List、Hash、Set、ZSet。
- 最后把单机配置替换成 Redis Cluster 配置,理解 Lettuce 的集群拓扑刷新配置。
这样从单机到集群,Spring Boot 集成 Redis 的基本流程就比较完整了。