使用jedis操作redis之消息的发布和订阅

来源:互联网 发布:php class unset 编辑:程序博客网 时间:2024/06/07 01:47

一般来说,发布和订阅(又称pub/sub)的特点是订阅者(listener)负责订阅频道(channel),发送者(publisher)负责向频道发送二级制字符串消息。每当有消息被发送至给定频道时,频道的所有订阅者都会受到消息。一个订阅者可以订阅多个频道,而发送者也能向多个频道发送消息。那么这里就分别来介绍命令行操作以及使用jedis操作redis来实现消息的发布和订阅。
关于使用jedis操作redis(参考使用jedis操作redis)。

一、命令行

使用ssh连接linux,打开三个窗口(一个发送消息,两个接收消息)启动redis服务,三个窗口都使用命令连接到redis客户端。

1、两个订阅者

127.0.0.1:6379> subscribe cctv1 Reading messages... (press Ctrl-C to quit)1) "subscribe"2) "cctv1"3) (integer) 1
127.0.0.1:6379> subscribe cctv1Reading messages... (press Ctrl-C to quit)1) "subscribe"2) "cctv1"3) (integer) 1

订阅频道 :subscribe 频道
两个订阅者都订阅了频道 “cctv1”

2、发送者

127.0.0.1:6379> publish cctv1 'haha'(integer) 2

向指定频道发送消息:publish 频道 消息内容
发送者向频道 “cctv1” 发送了一个消息, 内容是 “haha”

这个时候再看两个订阅者都已经接收到了这个消息

127.0.0.1:6379> subscribe cctv1Reading messages... (press Ctrl-C to quit)1) "subscribe"2) "cctv1"3) (integer) 11) "message"2) "cctv1"3) "haha"
127.0.0.1:6379> subscribe cctv1 Reading messages... (press Ctrl-C to quit)1) "subscribe"2) "cctv1"3) (integer) 11) "message"2) "cctv1"3) "haha"

2、jedis操作

创建项目,导包

<dependencies>    <dependency>            <groupId>redis.clients</groupId>            <artifactId>jedis</artifactId>            <version>2.8.1</version>        </dependency>     <dependency>          <groupId>junit</groupId>          <artifactId>junit</artifactId>          <version>4.11</version>       </dependency>  </dependencies>

测试(只做简单测试,不再说场景应用):

需求:两个订阅者(订阅相同的频道),三个发送者。发送者每次发送消息,订阅者接收到消息后将消息打印到控制台。

public class PubSubTest {    JedisPool jedispool = new JedisPool("192.168.25.128",6379);    Jedis jedis;    @Before//test方法执行之前执行    public void init(){        jedis = jedispool.getResource();    }    @After//test方法执行之后执行    public void destroy(){        jedispool.close();        jedis.close();    }    /*     * 测试订阅     */    @Test//订阅者1    public void test0() throws IOException{        MyJedisSub myJedisSub = new MyJedisSub();        jedis.subscribe(myJedisSub, "china-1","china-2","china-3");        System.in.read();//持续接收消息的状态,按回车线程才会结束。    }    @Test//订阅者2    public void test1() throws IOException{        MyJedisSub myJedisSub = new MyJedisSub();        jedis.subscribe(myJedisSub, "china-1","china-2","china-3");        System.in.read();    }

解释:jedis的subscribe方法要求传入第一个参数为JedisPubSub对象,该对象中定义了一系列消息监等听方法,需要我们自己定义类继承并实现需要的方法,如onMessage()。
第二个参数是订阅的频道。每次发送者向该频道发送消息后,可以在JedisPubSub的方法里面进行逻辑操作。比如这里监听到了消息,那么就在控制台打印消息。

自定义MyJedisSub类如下

public class MyJedisSub extends JedisPubSub{    @Override    public void onMessage(String channel, String message) {    //每次监听到频道channel发送的消息message后就在控制台打印        System.out.println("频道"+channel+"发出消息:"+message);    }}
    /*     * 测试发布消息     */    @Test//发布者1    public void test2(){        jedis.publish("china-1", "正在播放新闻联播");    }    @Test//发布者2    public void test3(){        jedis.publish("china-2", "正在播放射雕英雄传");    }    @Test//发布者3    public void test4(){        jedis.publish("china-3", "正在播放还珠格格");    }

测试:先运行test0和test1方法,使用订阅者处于一直接受消息的状态。在分别运行test2-test4。可以在两个订阅者对应的控制台看到打印的消息。

订阅者1控制台:

这里写图片描述

订阅者2控制台:

这里写图片描述

注意:redis的发布与订阅模式非常有用,但是存在着一些问题。一个是因为旧版本的不稳的性原因(如果一个客户端订阅了某些频道,但它读取的速度不够快的话,那么不断积累的消息就会导致redis输出缓冲区的体积变得越来越大,这会导致redis速度变慢,甚至崩溃)。另一个原因和数据传输的可靠性有关,比如客户端在订阅操作过程中断线,那么客户端就会丢失在断线期间发生的所有消息(来自redis in action这本书,同时提供了解决办法)。