暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

SpringBoot集成Redis Messaging (Pub/Sub)

编程新说 2021-09-03
1607

现在几乎所有的系统都会用到Redis,但并不是所有的系统都会用到消息队列。如果想使用消息队列,但又不想单独安装一个,可以使用Redis的消息队列功能。


Redis Messaging (Pub/Sub)


Redis消息队列一共只有六个命令,可以分为三类:

一、和订阅相关的命令

1、订阅一个或多个具体的channel:

SUBSCRIBE channel [channel ...]


四个订阅者,两个订阅like-man,两个订阅like-woman。

2、订阅一个或多个含有通配符的pattern:

PSUBSCRIBE pattern [pattern ...]


两个订阅者,都订阅like-*。

其中,通配符支持以下情况:

h?llo可以对应hello、hallo和hxllo

h*llo可以对应hllo和heeeello

h[ae]llo可以对应hello和hallo,但不能对应hillo

3、取消订阅一个或多个具体的channel:

UNSUBSCRIBE [channel [channel ...]]

备注:如果不指定channel,则取消订阅所有channel。

4、取消订阅一个或多个含有通配符的pattern:

PUNSUBSCRIBE [pattern [pattern ...]]

备注:如果不指定pattern,则取消订阅所有pattern。

二、和发布相关的命令

发布一个message到具体的channel:

PUBLISH channel message


向like-man发送一个消息handsome。


有四个订阅者接收到该消息,分别是两个订阅like-man的和两个订阅like-*的。


向like-woman发送一个消息sexy。


有四个订阅者接收到该消息,分别是两个订阅like-woman的和两个订阅like-*的。

三、和自省相关的命令

列出活跃的channel:

PUBSUB CHANNELS [pattern]

可以指定一个pattern或不指定,不指定时列出所有。


备注:活跃的channel是指至少有一个订阅者的。

列出channel的订阅者个数:

PUBSUB NUMSUB [channel-1 ... channel-N]

至少要指定一个channel,可以指定多个。


两个channel分别都有两个订阅者。


使用SpringBoot发布Redis消息


发布消息就是发送消息,这个比较简单,使用RedisTemplate即可。




使用SpringBoot订阅Redis消息


订阅消息就是接收消息,这个比较复杂。既有对Redis连接的管理,也有对消费消息的线程池的管理。不过Spring已经把这个“重活”给干了。

Spring提供了一个全套的解决方案,这里面包括:

1、订阅/取消订阅这些相关的用户操作

2、接收所有来自Redis的消息

3、把这些消息按照订阅关系分发给具体的消费者

4、触发消费消息的回调代码在线程池中运行

由于Spring已经全权代理,用户只需要提供要消费的topic以及对应的消费回调代码即可。

我们需要了解Spring提供的几个接口和类,才可以很好的使用:

Topic接口,表示一个订阅对象:


它有两个实现类,ChannelTopic和PatternTopic,前者对应redis的channel,后者对应redis的pattern。



MessageListener接口,回调接口,通过它来执行业务代码:


Message接口,表示从redis接收到的消息:


RedisMessageListenerContainer类,这个核心类,相当于一个代理,就是它负责接收redis的消息,并分发给MessageListener。

这个类需要一个RedisConnectionFactory,即redis连接工厂,用来获取一个redis连接,由于这个连接用于接收消息,所以它是一直阻塞着的。

还可以为这个类指定一个Executor,即线程池,这不是必须的,如果不指定它会生成一个默认的。


具体的配置代码


明白了原理后,就会变得很简单。我们只需成对的提供Topic和MessageListener即可,Topic告诉Spring要接收什么消息,MessageListener告诉Spring如何消费这些消息。

所以,我们自己定义一个接口,用于把它俩封装起来,接口名为MessageConsumer,即消息消费者。


我们只需实现该接口,并把实现类注册为Bean,就成为了一个消费者了。

LikeMan消费者


LikeWoman消费者


LikeBoth消费者


最后需要注册核心类(RedisMessageListenerContainer)为Bean,然后再收集到所有注册的消费者(MessageConsumer)Bean,并把它们添加到核心类里面即可。



看看执行情况


当没有启动Spring的时候,redis里没有订阅。


当启动好Spring的时候,redis里已经有了我们的两个订阅。


可以看到like-man和like-woman都各自有一个订阅者。


可以看到订阅的pattern只有一个。


我们向like-man发送一个消息,提示有两个订阅者收到了该消息。


可以看到订阅like-man的和订阅like-*的都收到了该消息。


同样向like-woman发送一个消息,也有两个订阅者收到了消息


同样订阅like-woman的和订阅like-*的都收到了该消息。



搞点其它尝试


我们再注册一份消费者,这样每个topic或pattern都有两个消费者。


发现redis里对于like-man和like-woman的订阅数并没有变。


那再来向like-man发个消息看看,发现还是两个订阅者收到了该消息。


再看看具体消费消息的情况,发现确实是四个消费者。


简单对比之后,我们发现了订阅者和消费者的关系是一对多的。

订阅描述的是接收消息的事情,消费描述的是使用消息的事情。

如果在Spring里有多个消费者订阅同一个topic,那么Spring和redis之间关于该topic只有一份订阅关系,所以消息只接收一次,只不过Spring再分别分发给多个消费者而已。这就是前面说的代理作用嘛。

那我们就启动两份Spring工程,这样就有两个和redis之间的连接,此时理论上订阅数量应该变成2了。


果然和我们猜想的一样。

站在Spring的角度来看:

1、Spring保证在它和redis之间的一条连接上,对于同一个topic,只会向redis订阅一次,但是该topic可以有多个消费者。

2、Spring从这条连接上接收到这个topic的消息后,分发给这个topic的所有消费者。

站在Redis的角度来看:

1、Redis保证它和客户端的一条连接上只会建立一个订阅通道,而且在客户端首次订阅时建立。

2、这个订阅通道和topic无关,它是被所有这个客户端的topic共用。

可以用一个粗略的比喻来说明一下:

1、订阅通道就是一条路。

2、topic就是一辆车。

3、消费者就是一个人。

它们之间的关系是:

多个人可以坐到一辆车上,多辆车可以走在一条路上。

各自的关注点是:

1、Redis主要关注路,只要路建立好了,多少车都可以走。

2、Spring主要关注车,只要车有了,多少人都可以坐。

3、用户代码主要关注人,因为人有了,多少业务都可以处理。

由此可见,对于同一件事情,在不同的层次看到的“景色”是不一样的。

总的来说:

Redis利用它维护的订阅关系,把一个topic的消息发送给所有订阅该topic的客户端。

客户端利用它维护的消费关系,把一个topic的消息发送个所有消费该topic的消费者。

消费者拿到一个topic消息,根据topic和消息内容来进行适合的业务处理。

一个人能够看到什么样的风景,取决于他所在的高度。

一个人想要看到什么风景,必须先达到与之对应的高度。



(END)


>>> 热门文章集锦 <<<


毕业10年,我有话说

我是一个协程

我是一个跳表

线程池开门营业招聘开发人员的一天

递归 —— 你值得拥有

迄今为止最好理解的ZooKeeper入门文章

基于角色的访问控制(RBAC)

11年码农的肺腑之言,如何成为一个优秀的程序员,送给渴望优秀的人

非著名架构师告诉你,代码该如何写,才能自己写的容易别人看的也不痛苦

迄今为止最硬核的「Java8时间系统」设计原理与使用方法

任何人都需要知道的「世界时间系统」构成原理,尤其开发人员

彻彻底底给你讲明白啥是SpringMvc异步处理

【面试】我是如何面试别人List相关知识的,深度有点长文

我是如何在毕业不久只用1年就升为开发组长的

爸爸又给Spring MVC生了个弟弟叫Spring WebFlux

【面试】我是如何在面试别人Spring事务时“套路”对方的

【面试】Spring事务面试考点吐血整理(建议珍藏)

【面试】吃透了这些Redis知识点,面试官一定觉得你很NB(干货 | 建议珍藏)

【面试】如果你这样回答“什么是线程安全”,面试官都会对你刮目相看(建议珍藏)

【面试】迄今为止把同步/异步/阻塞/非阻塞/BIO/NIO/AIO讲的这么清楚的好文章(快快珍藏)

【面试】一篇文章帮你彻底搞清楚“I/O多路复用”和“异步I/O”的前世今生(深度好文,建议珍藏)

【面试】如果把线程当作一个人来对待,所有问题都瞬间明白了

Java多线程通关———基础知识挑战

品Spring:帝国的基石



文章转载自编程新说,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论