Redis发布订阅机制&&底层原理概述&&java代码实现发布订阅小demo

发布订阅概述
消息发布者发布消息,
消息订阅者接收消息,
二者通过某种媒介关联起来。
首先要有消息的发布者,其次要有消息的订阅者。有了消息发布者和订阅者之后,还需要中间的媒介类似频道channel。

发布订阅机制
redis发布订阅功能用于消息的传输;redis发布订阅机制包含3个部分:发布者,订阅者,channel(频道)。

当一个客户端通过 PUBLISH 命令向订阅者发送信息的时候,我们称这个客户端为发布者(publisher)。
而当一个客户端使用 SUBSCRIBE 或者 PSUBSCRIBE命令接收信息的时候,我们称这个客户端为订阅者(subscriber)。
为了解耦发布者(publisher)和订阅者(subscriber)之间的关系,Redis 使用了 channel (频道)作为两者的中介 —— 发布者将信息直接发布给 channel ,而 channel 负责将信息发送给适当的订阅者,发布者和订阅者之间没有相互关系,也不知道对方的存在。

在这里插入图片描述

如上图所示,Client AClient B 订阅了 channel,当 Client C通过 channel发布消息 mess 时,Client AClient B 就会收到该消息。

底层原理
关于底层原理,我想单独拉出写篇博客,发现是要通过分析 Redis 源码里的 pubsub.c 文件才行,Redis是使用C实现的,,但是我还是想写,所以这里简单概述一下。
Redis 通过 PUBLISH 、SUBSCRIBE 和 PSUBSCRIBE 等命令实现发布和订阅功能。
通过 SUBSCRIBE 命令订阅某频道后,redis-server 里维护了一个字典,字典的键就是一个个 channel ,而字典的值则是一个链表,链表中保存了所有订阅这个 channel 的客户端。SUBSCRIBE 命令的关键,就是将客户端添加到给定 channel 的订阅链表中。
通过 PUBLISH 命令向订阅者发送消息,redis-server 会使用给定的频道作为键,在它所维护的 channel 字典中查找记录了订阅这个频道的所有客户端的链表,遍历这个链表,将消息发布给所有订阅者。

命令
Redis 发布订阅模式(pub/sub mode) 是一种消息通信模式
Redis 客户端可以订阅任意数量的频道
发送者(Publisher)发送消息
订阅者(Subsciber)接收消息

subscribe
使用subscribe,订阅给定的一个或多个频道

subscribe z1 z2 z3
Reading messages... (press Ctrl-C to quit) 
  1) "subscribe" # 订阅反馈 
  2) "z1" # 订阅的频道 
  3) (integer) 1 # 目前客户端已订阅频道/模式的数量 

  1) "message" # 信息 
  2) "z1" # 发送信息的频道 
  3) " hello zsl " # 信息内容```

1) "message" # 信息 
  2) "z2" # 发送信息的频道 
  3) " hello zsl2" # 信息内容```

1) "message" # 信息 
  2) "z3" # 发送信息的频道 
  3) " hello zsl3 " # 信息内容

在这里插入图片描述

publish
使用publish,用于向给定的频道发送信息,返回值为接收到信息的订阅者数量

Centos6.5.6379:0>publish z1 "hello zsl"
"1"
Centos6.5.6379:0>publish z2 "hello zsl2"
"1"
Centos6.5.6379:0>publish z3 "hello zsl3"
"1"

在这里插入图片描述

psubscribe
模式订阅消息
使用psubscribe,订阅消息的时候还可以通过模式匹配订阅的方式订阅,
比如说,使用 zsl.* 为输入,就可以订阅所有以 zsl. 开头的频道,比如 zsl.yx 、 zsl.blog 、 zsl.np ,

psubscribe zsl.*
 Reading messages... (press Ctrl-C to quit) 
  1) "psubscribe" 
  2) "zsl.*" 
  3) (integer) 1 
	
	1) "pmessage" 
  2) "zsl.*" # 匹配的模式 
  3) "zsl.np" # 消息的来源频道 
  4) "zsl niupi" # 消息内容 

  1) "pmessage" 
  2) "zsl.*" 
  3) "zsl.youxiu" 
  4) "zsl youxiu" 

在这里插入图片描述在这里插入图片描述

java实现redis发布订阅小demo

Publisher发布者

@Component
public class Publisher extends Thread{
	@Autowired
	private  JedisPool jedisPool;
	 
    public Publisher(JedisPool jedisPool) {
        this.jedisPool = jedisPool;
    }
 
	
    
    @Override
    public void run(){
    	
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        Jedis jedis = jedisPool.getResource();   //连接池中取出一个连接
        while (true) {
            String line;
            try {
                line = reader.readLine();
                if (!"quit".equals(line)) {
                    jedis.publish("mychannel", line);   //从通过mychannel 频道发布消息
                    System.out.println(String.format("发布消息成功!channel: %s, message: %s", "mychannel", line));
                } else {
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

MsgListener监听

@Component
public class MsgListener extends JedisPubSub{

	@Override
	public void onMessage(String channel, String message) {
		// TODO Auto-generated method stub
		System.out.println("收到消息成功!channel:"+channel+"msg:"+message);
        this.unsubscribe();
	}

	@Override
	public void onPMessage(String pattern, String channel, String message) {
		// TODO Auto-generated method stub
		super.onPMessage(pattern, channel, message);
	}

	@Override
	public void onSubscribe(String channel, int subscribedChannels) {
		// TODO Auto-generated method stub
        System.out.println(String.format("订阅频道成功! channel: %s, subscribedChannels %d",
        channel, subscribedChannels));
	}

	@Override
	public void onUnsubscribe(String channel, int subscribedChannels) {
		// TODO Auto-generated method stub
        System.out.println(String.format("取消订阅频道! channel: %s, subscribedChannels: %d",
                channel, subscribedChannels));
	}

	@Override
	public void onPUnsubscribe(String pattern, int subscribedChannels) {
		// TODO Auto-generated method stub
		super.onPUnsubscribe(pattern, subscribedChannels);
	}

	@Override
	public void onPSubscribe(String pattern, int subscribedChannels) {
		// TODO Auto-generated method stub
		super.onPSubscribe(pattern, subscribedChannels);
	}
	
	
}

Subscriber订阅者

@Component
public class Subscriber extends Thread{
	@Resource
	private JedisPool jedisPool;
    private final MsgListener msgListener = new MsgListener();
 
    private final String channel = "mychannel";
 
    public Subscriber(JedisPool jedisPool) {
        super("Subscriber");
        this.jedisPool = jedisPool;
    }
 
    @Override
    public void run() {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();   //取出一个连接
            jedis.subscribe(msgListener, channel);    //通过subscribe的api去订阅,参数是订阅者和频道名
 
            //注意:subscribe是一个阻塞的方法,在取消订阅该频道前,会一直阻塞在这,无法执行后续的代码
            //这里在msgListener的onMessage方法里面收到消息后,调用了this.unsubscribe();来取消订阅,才会继续执行
            System.out.println("继续执行后续代码。。。");
 
        } catch (Exception e) {
            System.out.println(String.format("subsrcibe channel error, %s", e));
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

偷偷学习被我发现

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值