使用redis客户端实现
Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。一个redis客户端可以订阅任意多大频道channel,一个频道也可以被多个客户端订阅。 1.创建并监听频道
- 通过指令SUBSCRIBE订阅一个频道,如果频道不存在时则新建一个频道,以下语句创建一个名称为mySubscribe的频道:
127.0.0.1:6379> SUBSCRIBE mySubscribe
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "mySubscribe"
3) (integer) 1
复制代码
- 此时创建了该频道的redis客户端监听了此频道,相当于一个订阅者。
2.向创建的频道发送一条消息
- 指令
PUBLISH channel message
负责向一个频道发送一条消息;打开一个新的redis客户端,向刚才创建的频道发送消息。
127.0.0.1:6379> publish mySubscribe "Redis is a great caching technique"
(integer) 1
复制代码
- 第一个redis客户端(创建并监听了频道mySubscribe)将会受到刚发布的这条消息
127.0.0.1:6379> SUBSCRIBE mySubscribe
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "mySubscribe"
3) (integer) 1
1) "message"
2) "mySubscribe"
3) "Redis is a great caching technique"
复制代码
Java使用Jedis实现redis的发布/订阅功能
同样实现上一篇文章中的例子
1.订阅者需要继承抽象类JedisPubSub;重写方法onMessage接收发布者发送的消息,
public class Farmer extends JedisPubSub{
private static final Logger logger = Logger.getLogger(pubsub.Farmer.class);
@Override
public void onMessage(String channel, String message) {
logger.info(String.format("client: FARMER. Message. Channel: %s, Msg: %s", channel, message));
if("rain".equals(message)){
logger.info("FARMER : a satisfied day!!!");
}else if("sunny".equals(message)){
logger.info("FARMER : a terrible day!!!");
}else {
logger.info("FARMER : Spam messages");
}
}
}
public class Worker extends JedisPubSub {
private static final Logger logger = Logger.getLogger(pubsub.Farmer.class);
@Override
public void onMessage(String channel, String message) {
logger.info(String.format("client: WORKER. Message. Channel: %s, Msg: %s", channel, message));
if("rain".equals(message)){
logger.info("WORKER : a satisfied day!!!");
}else if("sunny".equals(message)){
logger.info("WORKER : a terrible day!!!");
}else {
logger.info("WORKER : Spam messages");
}
}
}
public class Programmer extends JedisPubSub {
private static final Logger logger = Logger.getLogger(pubsub.Farmer.class);
@Override
public void onMessage(String channel, String message) {
logger.info(String.format("client: PROGRAMMER. Message. Channel: %s, Msg: %s", channel, message));
if("rain".equals(message)){
logger.info("PROGRAMMER : a satisfied day!!!");
}else if("sunny".equals(message)){
logger.info("PROGRAMMER : a terrible day!!!");
}else {
logger.info("PROGRAMMER : Spam messages");
}
}
}
复制代码
2.定义发布者
public class WeatherServer{
public void publishMessage(Jedis jedis,String channel,String msg) {
jedis.publish(channel,msg);
}
}
复制代码
3.测试类
public class Main {
public static final String CHANNEL_NAME = "MyChannel";
public static final String REDIS_HOST = "localhost";
public static final int REDIS_PORT = 6379;
private final static Logger logger = Logger.getLogger(Main.class);
private final static JedisPoolConfig POOL_CONFIG = new JedisPoolConfig();
private final static JedisPool JEDIS_POOL =
new JedisPool(POOL_CONFIG, REDIS_HOST, REDIS_PORT, 0);
public static void main(String[] args) throws Exception {
PropertyConfigurator.configure("src/log4j.properties");
/*订阅者redis客户端*/
final Jedis farmerJedis = JEDIS_POOL.getResource();
final Jedis workerJedis = JEDIS_POOL.getResource();
final Jedis programmerJedis = JEDIS_POOL.getResource();
/*发布者redis*/
final Jedis publisherJedis = JEDIS_POOL.getResource();
final Farmer farmer = new Farmer();
final Worker worker = new Worker();
final Programmer programmer = new Programmer();
//订阅线程:接收消息,因为Jedis是以阻塞的方式等待发布者消息的,所以每个Jedis客户端必须对应一个独立的线程。不然只会有第一个Jedis接受到消息。
new Thread(new Runnable() {
public void run() {
try {
farmerJedis.subscribe(farmer,CHANNEL_NAME);
logger.info("Subscription ended.");
} catch (Exception e) {
logger.error("Subscribing failed.", e);
}
}
}).start();
new Thread(new Runnable() {
public void run() {
try {
workerJedis.subscribe(worker,CHANNEL_NAME);
logger.info("Subscription ended.");
} catch (Exception e) {
logger.error("Subscribing failed.", e);
}
}
}).start();
new Thread(new Runnable() {
public void run() {
try {
programmerJedis.subscribe(programmer,CHANNEL_NAME);
logger.info("Subscription ended.");
} catch (Exception e) {
logger.error("Subscribing failed.", e);
}
}
}).start();
//主线程:发布消息到CHANNEL_NAME频道上
WeatherServer weatherServer = new WeatherServer();
weatherServer.publishMessage(publisherJedis,CHANNEL_NAME,"rain");
farmerJedis.close();
workerJedis.close();
programmerJedis.close();
}
}
复制代码
订阅者是根据channel的名字接收发布者发布的消息的。