发布和订阅
- 什么是发布和订阅?
- 发布订阅是一种应用程序(系统)之间通讯,传递数据的技术手段。特别是在异构(不同语言)系统之间作用非常明显。发布订阅可以是实现应用(系统)之间的解耦合。
- 发布订阅:类似微信中关注公众号/订阅号,公众号/订阅号发布的文章,信息。订阅者能及时获取到最新的内容。微博的订阅也是类似的。日常生活中听广播,看电视。都需要有信息的发布者,收听的人需要订阅(广播、电视需要调动某个频道)。发布订阅是一对多的关系。
- 订阅:对某个内容感兴趣,需要实时获取新的内容。只要关注的内容有变化就能立即得
到通知。多的一方。 - 发布:提供某个内容,把内容信息发送给多个对此内容感兴趣的订阅者。是有主动权,是一的一方。
- 发布订阅应用在即时通信应用中较多,比如网络聊天室,实时广播、实时提醒等。滴滴打车软件的抢单;外卖的抢单;在微信群发红包,抢红包都可以使用发布订阅实现。
Redis的发布和订阅
Redis发布订阅(pub/sub)是一种消息通信模式:发送者(publish)发送消息,订阅者(subscribe)接收消息。发布订阅也叫生产者消费者模式,是实现消息队列的一种方式。
如何实现
-
发布订阅的相关命令:
A、publish发布消息
语法:publish chanel message
作用:将message消息发送到channel频道。message是要发送的消息,channel是自定
义的频道名称(例如cctv1,cctv5),唯一标识发布者。
返回值:数字。接收到消息订阅者的数量B、subscribe订阅频道
语法:subscribe channel [channel…]
作用:订阅一个或多个频道的信息
返回值:订阅的消息
C、unsubscribe退订频道语法:unsubscribe channel [channel]
作用:退出指定的频道,不订阅。
返回值:退订的告知消息命令行实现
注意要启动订阅者,等待接收发布者的消息,否则订阅者接收不到消息
A、开启4个redis客户端,3个客户端作为消息订阅者,1个为消息发布者
B、让3个消息订阅者订阅某个频道主题:subscribe channel
在订阅者的三个窗口中分别启动redis客户端,redis安装目录/src下执行./redis-cli
C、让1个消息发布者向频道主题上发布消息:publish channel message在发布者窗口
D、 然后观察消息的发布和订阅情况,在任意一个订阅窗口
编程实现
-
JedisPubSub类:Jedis中的JedisPubSub类是Jedis的一个抽象类,此类定义了publish/subscribe的回调方法,通过继承JedisPubSub类,重写回调方法。实现java中Redis的发布订阅。当Reids发生发布或订阅的相关事件时会调用这些回调方法。只在回调方法中实现自己的业务逻辑。
-
onMessage():发布者发布消息时,会执行订阅者的回调方法onMessage(),接收发布的消息。在此方法实现消息接收后的,自定义业务逻辑处理,比如访问数据库,更新库存等。
A、订阅者SUB工程,订阅者MyRedisSubScribe继承 JedisPubSub
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
public class MyRedisSubScribe extends JedisPubSub {
/**
* 当订阅者接收到消息时回自动调用改方法
* @param channel 频道的名称
* @param message 发布的消息
*/
@Override
public void onMessage(String channel, String message) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("我是订阅者:订阅频道[" + channel + "],收到的消息是:[" + message + "],时间为:[" + df.format(new Date()) + "]");
}
public static void main(String[] args) {
// 创建Jedis
Jedis jedis = new Jedis("127.0.0.1", 6379);
// 密码认证
jedis.auth("123456");
// 创建redisSubScribe对象
MyRedisSubScribe redisSubScribe = new MyRedisSubScribe();
// 从Redis订阅 cctv6
jedis.subscribe(redisSubScribe, "cctv6");
}
}
B、 发布者工程,定义MyRedisPublish发布消息
import redis.clients.jedis.Jedis;
public class MyRedisPublish {
public static void main(String[] args) {
// 创建Jedis
Jedis jedis = new Jedis("127.0.0.1", 6379);
jedis.auth("123456");
jedis.publish("cctv6", "战狼2");
System.out.println("发布消息完毕....");
}
}
C、 执行程序,先启动订阅者,在运行发布者
Redis发布订阅与ActiveMQ的比较
(1)ActiveMQ支持多种消息协议,包括AMQP,MQTT,Stomp等,并且支持JMS规范,但Redis没有提供对这些协议的支持;
(2)ActiveMQ提供持久化功能,但Redis无法对消息持久化存储,一旦消息被发送,如果没有订阅者接收,那么消息就会丢失;
(3)ActiveMQ提供了消息传输保障,当客户端连接超时或事务回滚等情况发生时,消息会被重新发送给客户端,Redis没有提供消息传输保障。