一.Redis 安装
redis安装可参考:http://www.runoob.com/redis/redis-install.html
二. 简介
Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
Redis 客户端可以订阅任意数量的频道。
下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:
当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:
三.基于java的redis使用示例
1.常量类
package redistest.npersistent;
public class Constants {
public static final String HOST = "127.0.0.1";// 本地服务器地址
public static final int PORT = 6379;// 端口
public static final String CHANNEL = "message-channel";// 消息通道(频道)
}
2.消息发布端类
package redistest.npersistent;
import redis.clients.jedis.Jedis;
/**
* 消息发布端
*
* @version 1.0
* @since JDK1.7
* @date 2017年9月6日 下午1:06:55
*/
public class PubClient {
private Jedis jedis;
// 连接redis服务器
public PubClient(String host, int port){
jedis = new Jedis(host, port);
}
/**
*
* 消息发布
*
* @param channel 消息通道
* @param message 消息体
*
* @date 2017年9月8日 上午10:09:43
*/
public void pub(String channel, String message){
jedis.publish(channel, message);
}
public void close(String channel){
jedis.publish(channel, "quit");
jedis.del(channel);
}
}
3.消息订阅端类
package redistest.npersistent;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
/**
*
* 消息订阅端
*
* @version 1.0
* @since JDK1.7
* @date 2017年9月6日 下午1:19:21
*/
public class SubClient {
private Jedis jedis;
public SubClient(String host, int port){
jedis = new Jedis(host,port);
}
/**
*
* 消息订阅
*
* @param listener jedisPubSub用于处理监听到的消息
* @param channel 要订阅的消息通道
*
* @date 2017年9月8日 上午10:49:06
*/
public void sub(JedisPubSub listener,String channel){
jedis.subscribe(listener, channel); // 订阅给定的一个或多个频道的信息
//此处将会阻塞,在client代码级别为JedisPubSub在处理消息时,将会“独占”链接
//并且采取了while循环的方式,侦听订阅的消息
//
}
}
4.订阅者消息处理器类
package redistest.npersistent;
import java.util.Date;
import common.DateUtil;
import redis.clients.jedis.JedisPubSub;
/**
*
* 订阅者消息处理器
* 1).要使用Jedis的Publish/Subscribe(发布/订阅)功能,必须编写对JedisPubSub的自己的实现
* 2).Redis为我们提供了publish/subscribe(发布/订阅)功能。我们可以对某个channel(频道)进行subscribe(订阅),当有人在这个channel上publish(发布)消息时,
* redis就会通知我们,这样我们可以收到别人发布的消息。
* 3).
*
* @version 1.0
* @since JDK1.7
* @date 2017年9月6日 下午1:23:17
*/
public class PrintListener extends JedisPubSub {
/**
* 取得订阅的消息后的处理
* 即:订阅得到的信息将会在lister的onMessage(…)方法中进行处理
*
* @param channel
*/
@Override
public void onMessage(String channel, String message) {
// 接收到订阅频道消息后,业务处理逻辑
// 此处对消息的处理只是简单的打印
String time = DateUtil.dateToString(new Date(), "yyyy-MM-dd HH:mm:ss:SSS");
System.out.println("message receive:" + message + ",channel:" + channel + "..." + time);
// 此处我们可以取消订阅 ,即如果从通道中接收到消息“quit” ,就取消订阅
if(message.equalsIgnoreCase("quit")){
this.unsubscribe(channel); // 取消频道订阅
System.out.println("取消频道订阅成功.......");
}
}
}
5.非持久化订阅测试
package redistest.npersistent;
import org.apache.commons.lang3.RandomStringUtils;
import redis.clients.jedis.JedisPubSub;
/**
*
* 非持久化订阅测试
* ===========================================================================================================================
* 一个Redis client发布消息,其他多个redis client订阅消息,发布的消息“即发即失”,redis不会持久保存发布的消息;
* 消息订阅者也将只能得到订阅之后的消息,通道中此前的消息将无从获得。
* ===========================================================================================================================
*
* @version 1.0
* @since JDK1.7
* @date 2017年9月6日 下午1:31:39
*/
public class PubSubTest {
public static void main(String[] args) throws Exception{
// 连接到redis服务器
PubClient pubClient = new PubClient(Constants.HOST, Constants.PORT); // 消息发布端
// 往消息通道中发布消息
pubClient.pub(Constants.CHANNEL, "订阅之前发送的消息:我是张三丰.......");
pubClient.pub(Constants.CHANNEL, "订阅之前发送的消息:嘻嘻嘻嘻嘻.......");
Thread.sleep(2000);
//消息订阅者非常特殊,需要独占链接,因此我们需要为它创建新的链接;
//此外,jedis客户端的实现也保证了“链接独占”的特性,sub方法将一直阻塞,
//直到调用listener.unsubscribe方法
Thread subThread = null;
for (int i = 0; i < 3; i++) {
subThread = new Thread(new Runnable() {
@Override
public void run() {
try{
// 消息订阅端
SubClient subClient = new SubClient(Constants.HOST, Constants.PORT);
System.out.println("----------订阅开始-------");
JedisPubSub listener = new PrintListener();// 订阅者消息处理器
// 在API级别,此处为【轮询操作】,直到unsubscribe调用,才会返回
subClient.sub(listener, Constants.CHANNEL);
System.out.println("----------订阅结束-------");
}catch(Exception e){
e.printStackTrace();
}
}
});
subThread.start();
}
int i = 0;
while (i < 10) {
String message = RandomStringUtils.random(6, true, true);//apache-commons
System.out.println("随机生成的字符串:" + message);
pubClient.pub(Constants.CHANNEL, message);
i++;
Thread.sleep(1000);
}
// 被动关闭指示,如果通道中,消息发布者确定通道需要关闭,那么就发送一个“quit”
// 那么在listener.onMessage()中接收到“quit”时,其他订阅client将执行“unsubscribe”操作。
pubClient.close(Constants.CHANNEL);
// 此外,你还可以这样取消订阅
// listener.unsubscribe(channel);
}
}