关于redis的发布订阅模式,大家应该都有听过,具体的我就不阐述了,其实本质和传统的MQ的发布订阅是差不多的,但是相对于其它几款MQ产品来说,redis的使用更加便捷,也更加轻量化,不需要单独去搭建集成一套繁重的MQ框架,但缺点也很明显,redis发布的消息不会持久化,所以当某一台服务器出现问题的时候,这个消息会被丢失掉,就会导致数据问题,所以在考虑使用之前要慎重,当前的业务是否对数据一致性要求很高,如果要求很高,还是建议使用MQ产品。
简单记录一下的使用方法。
首先是环境,注意redis的版本需要在2.0以上就可以支持发布订阅模式了,项目环境就不说了,一个简单的springBoot工程,我的版本是2.1.1。
其实整个使用过程比较简单,只需要明白几个点就可以了,第一点是消息发布给谁?第二点是订阅消息的主体是谁?解决这两个问题之前,我们先看一下redisTemplate中发布消息的方法convertAndSend(),这个方法有两个参数:channel和message,message自然就是我们发送的消息内容,channel顾名思义即一个消息通道,用来连接订阅者的通道,这里需要有一个Topic(主题)的概念,Topic分为指定主题ChannelTopic和模糊主题PatternTopic,两者的区别就是一个明确指定订阅主体,一个可以模糊匹配订阅主体。所以当有了一个Topic后在发布消息的时候就可以知道是发给谁的了,也就知道了订阅方是谁了。
所以下一步需要做的就是将Topic和订阅者绑定起来。在redis的配置文件中将二者关联起来。
首先我们构建一个监听类用来订阅消息
@Slf4j
public class SubListener {
}
redis配置文件
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
/** redis发布/订阅模式配置*/
@Bean
public ChannelTopic pubTopic() {
return new ChannelTopic("pub");
}
@Bean
public SubListener subListener() {
return new SubListener();
}
/**
* redis消息容器
*/
@Bean
public RedisMessageListenerContainer container(RedisConnectionFactory redisConnectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
// 设置redis连接工厂
container.setConnectionFactory(redisConnectionFactory);
// 绑定订阅主题和监听器
container.addMessageListener(subListener(), pubTopic());
return container;
}
}
在绑定主题和订阅者的时候会报错提示需要实现MessageListener接口中的onMessage方法,所以我们过去实现就可以了,当你收到订阅消息时,就可以在onMessage中进行处理。
至此,发布与订阅的关系就绑定上了,当在发布消息时使用该主题"pub"时,对应的SubListener就会收到消息。
主题可以配置多个,以用来处理不同的业务,使用上只需要注入主题选择对应的主题发送消息即可。
@Component
public class RedisCache {
@Autowired
public RedisTemplate redisTemplate;
@Autowired
@Qualifier("channelTopic")
public ChannelTopic channelTopic;
@Autowired
@Qualifier("simpleDataTopic")
public ChannelTopic simpleDataTopic;
@Autowired
@Qualifier("settingTopic")
public ChannelTopic settingTopic;
/**
* redis发布消息 使用对应的主题发送消息,对应的订阅者便会收到消息
*/
public void convertAndSend(Object message) {
redisTemplate.convertAndSend(channelTopic.getTopic(), message);
}
public void simpleDataTopicSend(Object message) {
redisTemplate.convertAndSend(simpleDataTopic.getTopic(), message);
}
public void settingTopicSend(Object message) {
redisTemplate.convertAndSend(settingTopic.getTopic(), message);
}
不足之处,或有问题之处还请指出。