hello云胜

技术与生活

0%

springboot中使用redis的发布订阅

redis的发布订阅模式

通常我们只把redis当缓存数据库来使用。但是redis从5版本开始增加了一个消息的发布订阅功能。

可以类比于一个简化版的消息队列。当然功能弱很多。之前我一直认为这个功能很鸡肋。直到最近负责一个项目,需要一个消息订阅的功能。如果再去搭建一个rocketmq感觉浪费服务器。使用redis的发布订阅也能解决问题。所以是我以前狭隘了,存在即合理。

下面简单介绍下redis的发布订阅

订阅频道

首先,客户端使用SUBSCRIBE命令来订阅一个或多个频道。例如,以下命令订阅了名为news的频道:

1
SUBSCRIBE news

客户端也可以同时订阅多个频道,例如:

1
SUBSCRIBE news sport weather

发布消息

使用PUBLISH命令可以向指定的频道发布一条消息。当消息发布到某个频道时,所有订阅该频道的客户端都会收到通知。(注意:所有订阅者都会收到)。例如,以下命令将消息hello world发布到名为news的频道:

1
PUBLISH news "hello world"

之前的订阅者客户端会显示

1
2
3
1) "message"
2) "news"
3) "hello world"

退订频道

如果客户端不再需要订阅某个频道,可以使用UNSUBSCRIBE命令来退订。例如,以下命令退订了名为news的频道:

1
UNSUBSCRIBE news

客户端也可以同时退订多个频道,例如:

1
UNSUBSCRIBE news sport weather

模式匹配订阅

除了订阅具体的频道外,客户端还可以使用通配符订阅一类频道。通配符*可以匹配任意字符串,而?则可以匹配单个字符。例如,以下命令订阅所有以news.为前缀的频道:

1
PSUBSCRIBE news.*

模式匹配退订

如果客户端不再需要订阅某类频道,可以使用PUNSUBSCRIBE命令来模式匹配退订。例如,以下命令退订所有以news.为前缀的频道:

1
PUNSUBSCRIBE news.*

好了,下面在代码里使用

springboot中使用redis的发布订阅

添加Redis依赖

首先,您需要在您的Spring Boot项目中添加Redis依赖。可以使用以下Maven依赖项:

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置Redis连接

接下来,需要配置Redis连接。在application.yml文件中添加以下内容:

1
2
3
4
5
6
spring:
redis:
cluster:
nodes: xxxx;xxxx;我用的是redis集群
max-redirects: 3
password: xxxxxxx

订阅频道

要订阅一个频道,需要在RedisConfig配置类中实例化一个RedisMessageListenerContainer类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Configuration
public class RedisConfig {

@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
MyMessageListener listener) {

RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(listener, new ChannelTopic("news"));

return container;
}
// 其他redis的配置代码,略
}

这里我们订阅了名为news的一个channel。

代码中MyMessageListener是自定义的listener,用于处理订阅接收到的消息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Component
public class PathAuthRedisMessageListener implements MessageListener {

@Autowired
private RedisTemplate redisTemplate;

@Override
public void onMessage(Message message, byte[] pattern) {
// 获取消息
byte[] messageBody = message.getBody();
// 使用值序列化器转换
Object msg = redisTemplate.getValueSerializer().deserialize(messageBody);
// 获取监听的频道
byte[] channelByte = message.getChannel();
// 使用字符串序列化器转换
Object channel = redisTemplate.getStringSerializer().deserialize(channelByte);
// 渠道名称转换
String patternStr = new String(pattern);
System.out.println(patternStr);
System.out.println("---频道---: " + channel);
System.out.println("---消息内容---: " + msg);
}
}

发布消息

要发布一条消息,也很简单。示例:

1
2
3
4
5
6
7
8
9
10
11
@RestController
public class MessageController {

@Autowired
private RedisTemplate template;

@PostMapping("/message")
public void sendMessage(@RequestParam String message) {
template.convertAndSend("news", message);
}
}

这样就可以将消息发布到news频道。

总结

总体来说,springboot里集成redis的发布订阅功能还是比较简单的。受限于redis发布订阅本身能力的限制,毕竟Redis不是专门做发布订阅的,比如redis的发布订阅不支持消息的持久化,消息丢了就是丢了。所以只适合在某些简单并且不重要的业务场景下使用。