1. Redis为我们提供了publish/subscribe(发布/订阅)功能。我们可以对某个channel(频道)进行subscribe(订阅),当有人在这个channel上publish(发布)消息时, Redis就会通知我们, 这样我们可以收到别人发布的消息。
2. 作为Java的Redis客户端, Jedis提供了publish/subscribe的接口。本文讲述如何使用Jedis来实现Redis的publish/subscribe。
3. Jedis定义了抽象类JedisPubSub, 在这个类中, 定义publish/subsribe的回调方法。通过继承JedisPubSub类并重新实现这些回调方法, 当publish/subsribe事件发生时, 我们可以定制自己的处理逻辑。
4. 新建一个名为JedisPubSub的Java项目, 拷入相关jar包, 并添加到build path
5. 自定义发布和订阅的回调类
package com.redis.publish;
import redis.clients.jedis.JedisPubSub;
/**
* 发布和订阅的回调类
*/
public class MyJedisPubSub extends JedisPubSub {
private String clientName;
public MyJedisPubSub(String clientName) {
this.clientName = clientName;
}
@Override
public void onMessage(String channel, String message) {
System.out.println(String.format("%s客户端, 订阅%s频道, 接受到的消息是: %s", clientName, channel, message));
}
@Override
public void onSubscribe(String channel, int subscribedChannels) {
System.out.println(String.format("%s客户端, 订阅%s频道, 一共订阅%d个频道", clientName, channel, subscribedChannels));
}
@Override
public void unsubscribe(String... channels) {
super.unsubscribe(channels); // 这个一定要有, 不然取消订阅不生效
for (String item : channels) {
System.out.println(String.format("%s客户端, 取消订阅%s频道", clientName, item));
}
}
@Override
public void onUnsubscribe(String channel, int subscribedChannels) {
System.out.println(String.format("%s客户端, 取消订阅%s频道, 还订阅%d个频道", clientName, channel, subscribedChannels));
}
}
6. Jedis的subscribe操作
6.1. Jedis的subscribe的声明如下
public void subscribe(final JedisPubSub jedisPubSub, final String… channels)
6.2. 第一个参数接受一个JedisPubSub对象, 第二个参数指定对哪个频道进行订阅。上例中, 我们把我们自定义的MyJedisPubSub对象传给subscribe方法。当publish/subscribe的事件发生时, 会自动调用我们MyJedisPubSub的方法。
6.3. 由于Jedis的subscribe操作是阻塞的, 因此, 我们另起一个线程来进行subscribe操作。
7. 自定义订阅和取消订阅类
package com.redis.publish;
import redis.clients.jedis.Jedis;
/**
* 订阅和取消订阅线程类
*/
public class SubscribeThread extends Thread {
private Jedis jedis;
private MyJedisPubSub myJedisPubSub;
private String[] channels;
public SubscribeThread(String clientName, String[] channels) {
this.jedis = new Jedis("192.168.25.138", 6379);
this.jedis.auth("lyw123456");
this.myJedisPubSub = new MyJedisPubSub(clientName);
this.channels = channels;
}
@Override
public void run() {
jedis.subscribe(myJedisPubSub, channels);
}
public void unsubscribe(String[] channels) {
myJedisPubSub.unsubscribe(channels);
}
}
8. 发布类
package com.redis.publish;
import redis.clients.jedis.Jedis;
/**
* 发布类, 同时启动2个订阅客户端
*/
public class RedisPublish {
public static void main(String[] args) {
String cctv = "cctv";
String ximalaya = "xi ma la ya";
Jedis jedis = new Jedis("192.168.25.138", 6379);
jedis.auth("lyw123456");
SubscribeThread lisi = new SubscribeThread("lisi", new String[] {cctv});
lisi.start();
SubscribeThread zhangsan = new SubscribeThread("zhangsan", new String[] {cctv, ximalaya});
zhangsan.start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
jedis.publish(cctv, "小冠快走");
jedis.publish(ximalaya, "贞观长歌");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
zhangsan.unsubscribe(new String[] {cctv, ximalaya});
jedis.publish(cctv, "新年快乐");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
lisi.unsubscribe(new String[] {cctv});
jedis.close();
}
}
9. 运行结果