核心代码:
Springboot下的redis发布订阅topic模式,与Springboot的Event事件有异曲同工之妙,但是redis的发布订阅可以用于分布式系统,但是Event只能在同一个JVM实例起作用,同时要注意的是,因为redis是面向分布式系统设计的,因此有多个JVM实例都订阅了同一个Topic的话,会产生重复消费,因此如果不需要重复消费的场景,在消费的时候一定要在消费的时候进行幂等校验。Event使用的博客在SpringBoot Event 事件监听,这两种消息队列可靠性都不是很高,因为没有持久化及消费ACK确认机制,所以对可靠性高的系统,建议还是引入消息队列,关于消息队列的博客,可以参考我之前的笔记RabbitMQ实战指南之消息可靠性和RabbitMQ实战指南之RabbitMQ架构及运转流程 主要有三步:
- 获取主题
- 主题添加订阅者
- 通过主题发布事件
RTopic<SomeObject> topic = redisson.getTopic("anyTopic");
topic.addListener(new MessageListener<SomeObject>() {
@Override
public void onMessage(String channel, SomeObject message) {
//..
.}
});
// in other thread or JVM
RTopic<SomeObject> topic = redisson.getTopic("anyTopic");
long clientsReceivedMessage = topic.publish(new SomeObject());
具体过程
订阅者实现
@Component
public class ProjectMessageRedisListener implements MessageListener<ContractPassedEvent> {
public static final String TOPIC = "ContractPassedEvent";
@Autowired
RedissonClient redissonClient;
@Override
public void onMessage(CharSequence channel, ContractPassedEvent msg) {
System.out.println("收到事件:" + msg);
}
}
//必须实现序列化接口
@Data
public class ContractPassedEvent implements Serializable {
private static final long serialVersionUID = -1L;
private String name;
}
注册订阅者
@Configuration
@EnableAsyncpublic
class WebMvcConfigure implements WebMvcConfigurer {
@Autowired
RedissonClient redissonClient;
@Bean("contractPassedTopic")
public RTopic contractPassedTopic(){
//注册监听
RTopic topic = redissonClient.getTopic(ProjectMessageRedisListener.TOPIC);
topic.addListener(ContractPassedEvent.class, projectMessageRedisListener);
return topic;
}
发布事件
@RunWith(SpringRunner.class)
@SpringBootTest(classes = WebSpringBootTestApplication.class)
public class ProjectMessageRedisListenerTest{
@Autowired
RTopic topic;
@Test
public void testRedisTopic(){
topic.publish(new ContractPassedEvent("A00-Nj-2021-01-289-002932"));
}
}
订阅到多个主题
// subscribe to all topics by `topic1.*` pattern
RPatternTopic<Message> topic1 = redisson.getPatternTopic("topic1.*");
int listenerId = topic1.addListener(new PatternMessageListener<Message>() {
@Override
public void onMessage(String pattern, String channel, Message msg) {
Assert.fail();
}
});
原理
订阅:
发布:
Redis 发布订阅功能的特性
Topic 模式监听器在重连到 Redis 服务器或者 Redis 服务器故障恢复时自动重新订阅。
- 消息的发送者与接收者之间通过 channel 绑定:channel 可以是确定的字符串,也可以基于模式匹配
- 客户端可以订阅任意多个channel
- 发送者发送的消息无法持久化,所以可能会造成消息丢失
- 由于消息无法持久化,所以,消费者无法收到在订阅channel之前发送的消息
- 发送者与客户端之间的消息发送与接收不存在 ACK 机制
Redis 发布订阅功能的适用场景
由于没有消息持久化与 ACK 的保证,所以,Redis 的发布订阅功能并不可靠。这也就导致了它的应用场景很有限,建议用于实时与可靠性要求不高的场景。例如:
消息推送
内网环境的消息通知