1.基本介绍

Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。

Redis 客户端可以订阅任意数量的频道。

hiredis进行频道订阅的方法_hiredis进行频道订阅的方法

publish(发布命令)

API:publish channel message

演示:

127.0.0.1:6379> publish cctv:5 "hello world"
(integer) 0 #订阅者个数

subscribe(订阅)

API:subscribe [channel]

演示:

开启两个客户端,一个客户端先订阅cctv:5这个频道,另一个客户端往这个频道发送消息,订阅者会接收到消息。

hiredis进行频道订阅的方法_redis_02

 

unsubcribe(取消订阅)

API:unsubcribe [channel] #取消订阅一个或多个频道

演示:

127.0.0.1:6379> unsubscribe cctv:5
1) "unsubscribe"
2) "cctv:5"
3) (integer) 0

其它常用API

psubscribe [pattern...]  #订阅模式
punsubscribe [pattern...] #退订制定的模式
pubsub channels #列出至少有一个订阅者的模式
pubsub numsub [channel...] #列出给定频道的订阅者数量
pubsub numpat #列出被订阅模式的数量

2.SpringBoot实现redis的订阅模式

(1)导入依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

(2)配置redis

spring:
  redis:
    host: localhost
    port: 6379

(3)redis监听配置

@Configuration
@AutoConfigureAfter({RedisReceiver.class})
public class RedisListenerConfig {
    /**
     * redis消息监听器容器
     * 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器
     * 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理
     *
     * @param connectionFactory
     * @param listenerAdapter
     * @return
     */
    @Bean
    RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
                                            MessageListenerAdapter listenerAdapter
    ) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);

        //可以添加多个 messageListener
        container.addMessageListener(listenerAdapter, new PatternTopic("test"));

        return container;
    }


    /**
     * 消息监听器适配器,绑定消息处理器,利用反射技术调用消息处理器的业务方法
     *
     * @param redisReceiver
     * @return
     */
    @Bean
    MessageListenerAdapter listenerAdapter(RedisReceiver redisReceiver) {
        System.out.println("消息适配器进来了");
        return new MessageListenerAdapter(redisReceiver, "receiveMessage");
    }

    /**
     * 使用默认的工厂初始化redis操作模板
     *
     * @param connectionFactory
     * @return
     */
    @Bean
    StringRedisTemplate template(RedisConnectionFactory connectionFactory) {
        return new StringRedisTemplate(connectionFactory);
    }
}

(4)消息处理类

@Component
public class RedisReceiver {
    /**
     * 这里是收到通道的消息之后执行的方法
     *
     * @param message
     */
    public void receiveMessage(String message) {
        System.out.println("消息来了:" + message);
    }
}

(5)测试类

@EnableScheduling
@Component
public class TestController {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 向redis消息队列test通道发布消息
     */
    @Scheduled(fixedRate = 1000)
    public void sendMessage() {
        stringRedisTemplate.convertAndSend("test", String.valueOf(Math.random()));
    }

}

测试结果如下:

消息来了:0.07573790224258636
消息来了:0.6782217218490485
消息来了:0.04274004820156474
消息来了:0.01991680494899495
消息来了:0.21214175193928786
消息来了:0.8152357687137979

(6)实现一个方法监听多个频道

@Bean
    RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
                                            MessageListenerAdapter listenerAdapter
    ) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);

        //可以添加多个 messageListener
        container.addMessageListener(listenerAdapter, new PatternTopic("test"));
        container.addMessageListener(listenerAdapter, new PatternTopic("test2"));

        return container;
    }

这样之前的receiveMessage方法会接收到来自test和test2两个频道的所有消息。

(7)实现不同方法监听不同频道

修改我们的配置类,增加消息的适配器参数,之前只有一个适配器参数,现在我们增加到两个。并把test3的频道交给第二个适配器接收。

@Bean
    RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
                                            MessageListenerAdapter listenerAdapter,
                                            MessageListenerAdapter listenerAdapter2
    ) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);

        //可以添加多个 messageListener
        container.addMessageListener(listenerAdapter, new PatternTopic("test"));
        container.addMessageListener(listenerAdapter, new PatternTopic("test2"));
        container.addMessageListener(listenerAdapter2, new PatternTopic("test3"));

        return container;
    }
    
    @Bean
    MessageListenerAdapter listenerAdapter(RedisReceiver redisReceiver) {
        System.out.println("消息适配器进来了");
        return new MessageListenerAdapter(redisReceiver, "receiveMessage");
    }

    @Bean
    MessageListenerAdapter listenerAdapter2(RedisReceiver redisReceiver) {
        System.out.println("消息适配器2进来了");
        return new MessageListenerAdapter(redisReceiver, "receiveMessage2");
    }

测试方法:

@EnableScheduling
@Component
public class TestController {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 向redis消息队列test通道发布消息
     */
    @Scheduled(fixedRate = 1000)
    public void sendMessage() {
        stringRedisTemplate.convertAndSend("test", String.valueOf(Math.random()));
        stringRedisTemplate.convertAndSend("test2", "hello world");
    }

    @Scheduled(fixedRate = 1000)
    public void sendMessage2() {
        stringRedisTemplate.convertAndSend("test3", "hello redis");
    }

}

测试结果如下:

消息来了:0.21550984623295588
消息来了:hello world
消息来了2:hello redis
消息来了:0.4472284248403804
消息来了:hello world
消息来了2:hello redis
消息来了:0.3441512587764187
消息来了:hello world
消息来了2:hello redis