简介
Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息,Redis提供了两种模式分别为:基于Channel的发布/订阅和基于Pattern的发布/订阅。
Redis 发布订阅功能的特性
- 消息的发送者与接收者之间通过Channel 绑定:Channel 可以是确定的字符串,也可以基于模式匹配
- 客户端可以订阅任意多个Channel发送者
- 发送的消息无法持久化,所以可能会造成消息丢失
- 由于消息无法持久化,所以,消费者无法收到在订阅Channel 之间发送的消息
- 发送者与客户端之间的消息发送与接收不存在 ACK 机制
Channel的发布/订阅
"发布/订阅"模式包含两种角色,分别是发布者和订阅者。发布者可以向指定的频道(channel)发送消息; 订阅者可以订阅一个或者多个频道(channel),所有订阅此频道的订阅者都会收到此消息。
发布消息
发布者发布消息的命令是 publish,语法为:publish channel message,例如向testchannel发送hello
说明:消息发送采用的是publish,发送成功返回值表示接收这条消息的订阅者数量。且发出去的消息不会被持久化,只有客户端订阅testchannel之后,才能接该频道的消息,之前的发送的消息是无法接收的。
订阅消息
订阅频道的命令是subscribe,可以同时订阅多个频道,用法是 subscribe channel1 channel2..
说明:
- subscirbe:消息类型
- testChannel:为channel的名称
- hello:为消息的内容
Pattern的发布/订阅
如果有某个/某些模式和这个频道匹配的话,那么所有订阅这个/这些频道的客户端也同样会收到信息。
下图展示了一个带有频道和模式的例子,其中it.news.*模式匹配了it.news.xinliang频道和 it.news.huofu频道,并且有不同的客户端分别订阅它们三个:
说明:当有信息发送到it.nes.huofu频道时,信息除了发送给 clientX和clientY 之外,还会发送给订阅it.news.*模式的client123和client256。
发布消息
发布者发布消息的命令是 publish,语法为:publish it.news.xiliang xiliang
订阅消息
PSUBSCRIBE pattern [pattern ...]
订阅一个或多个符合给定模式的频道。
订阅为it.news.*当it.news.xiliang和it.news.huofu发送消息,通过匹配都能获取到消息。
Spring Boot集成
jar包引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
消息订阅配置
@Configuration
public class RedisConfig
{
@Autowired
private RedisConnectionFactory factory;
@Bean("redisTemplate")
public RedisTemplate<String, Object> redisTemplate()
{
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
//设置hash类型
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(factory);
return redisTemplate;
}
@Bean
RedisMessageListenerContainer container (RedisConnectionFactory redisConnectionFactory, MessageListenerAdapter listenerAdapter){
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(redisConnectionFactory);
//订阅消息
container.addMessageListener(listenerAdapter,new PatternTopic("defaultTopic"));
return container;
}
@Bean
MessageListenerAdapter listenerAdapter(RedisReceiver receiver)
{
return new MessageListenerAdapter(receiver, "receiveMessage");
}
}
说明:addMessageListener方法为注册监听,PatternTopic为订阅消息的channel RedisReceiver:定义消息的接收者
消息发送
public boolean convertAndSend(String channel, Object message)
{
if (!StringUtils.hasText(channel))
{
return false;
}
try {
redisTemplate.convertAndSend(channel, message);
logger.info("发送消息成功,channel:{},message:{}", channel, message);
return true;
} catch (Exception e)
{
logger.error("发送消息失败,channel:{},message:{}", channel, message);
}
return false;
}
//消息发送
@Component
public class MessageSend
{
@Autowired
private RedisUtil redisUtil;
public void sendMessage()
{
for (int i = 0; i < 5; i++) {
redisUtil.convertAndSend("defaultTopic",String.valueOf(new Random().nextInt(100)));
}
}
}
说明:通过调用convertAndSend方法发送消息。
消息接收
@Component
public class RedisReceiver
{
private static final Logger logger = LoggerFactory.getLogger(RedisUtil.class);
public void receiveMessage(String message)
{
logger.info("subscribe receive message:"+message);
}
}
说明:消息接收者,已经在RedisConfig进行注册,可以通过MessageListener实现
总结
本文讲解了Redis的消息订阅功能,由于Redis的消息无法持久化,所以使用的场景有限,如有疑问,请随时反馈。