SpringBoot使用Redis实现消息订阅

978 阅读3分钟

简介

Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息,Redis提供了两种模式分别为:基于Channel的发布/订阅和基于Pattern的发布/订阅。

Redis 发布订阅功能的特性

  • 消息的发送者与接收者之间通过Channel 绑定:Channel 可以是确定的字符串,也可以基于模式匹配
  • 客户端可以订阅任意多个Channel发送者
  • 发送的消息无法持久化,所以可能会造成消息丢失
  • 由于消息无法持久化,所以,消费者无法收到在订阅Channel 之间发送的消息
  • 发送者与客户端之间的消息发送与接收不存在 ACK 机制

Channel的发布/订阅

"发布/订阅"模式包含两种角色,分别是发布者和订阅者。发布者可以向指定的频道(channel)发送消息; 订阅者可以订阅一个或者多个频道(channel),所有订阅此频道的订阅者都会收到此消息。

图片.png

发布消息

发布者发布消息的命令是 publish,语法为:publish channel message,例如向testchannel发送hello

图片.png

说明:消息发送采用的是publish,发送成功返回值表示接收这条消息的订阅者数量。且发出去的消息不会被持久化,只有客户端订阅testchannel之后,才能接该频道的消息,之前的发送的消息是无法接收的。

订阅消息

订阅频道的命令是subscribe,可以同时订阅多个频道,用法是 subscribe channel1 channel2..

图片.png

说明:

  • subscirbe:消息类型
  • testChannel:为channel的名称
  • hello:为消息的内容

Pattern的发布/订阅

如果有某个/某些模式和这个频道匹配的话,那么所有订阅这个/这些频道的客户端也同样会收到信息。

下图展示了一个带有频道和模式的例子,其中it.news.*模式匹配了it.news.xinliang频道和 it.news.huofu频道,并且有不同的客户端分别订阅它们三个:

图片.png

说明:当有信息发送到it.nes.huofu频道时,信息除了发送给 clientX和clientY 之外,还会发送给订阅it.news.*模式的client123和client256。

发布消息

发布者发布消息的命令是 publish,语法为:publish it.news.xiliang xiliang

图片.png

订阅消息

 PSUBSCRIBE pattern [pattern ...]

订阅一个或多个符合给定模式的频道。

图片.png

订阅为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的消息无法持久化,所以使用的场景有限,如有疑问,请随时反馈。