发布订阅(pub/sub)是一种消息通信模式,主要的目的是解耦消息发布者和消息订阅者之间的耦合,这点和设计模式中的观察者模式比较相似。pub /sub不仅仅解决发布者和订阅者直接代码级别耦合也解决两者在物理部署上的耦合。Redis作为一个pub/sub server,在订阅者和发布者之间起到了消息路由的功能。订阅者可以通过subscribe和psubscribe命令向redis server订阅自己感兴趣的消息类型,redis将消息类型称为频道(channel)。当发布者通过publish命令向redis server发送特定类型的消息时。订阅该消息类型的全部client都会收到此消息。这里消息的传递是多对多的。一个client可以订阅多个 channel,也可以向多个channel发送消息。
==================================================
==================================================================
由于redis内置了发布/订阅功能,可以作为消息机制使用。
普通订阅
void redis.clients.jedis.Jedis.subscribe(JedisPubSub jedisPubSub, String... channels)
模式订阅
void redis.clients.jedis.Jedis.psubscribe(JedisPubSub jedisPubSub, String... patterns)
普通订阅和模式订阅,都可以订阅一个或多个的频道。
二者的区别是,模式订阅支持 * 作为匹配符。比如 it* 匹配所有以 it 开头的频道( it.news 、 it.blog 、 it.tweets 等等)。 news.* 匹配所有以 news. 开头的频道( news.it 、 news.global.today 等等),诸如此类。
通配符说明:
* 0到任意多个字符
? 1个字符
测试代码:
两个Client,分别订阅一些频道。
一个Publish。负责发布消息到指定频道。
Publish
public static void main(String[] args) { Jedis jedis = new Jedis("10.110.20.152",6379); jedis.publish("china.beijing", "中国北京"); jedis.publish("china.jinan", "中国济南"); jedis.publish("it.software", "软件"); jedis.publish("test1", "测试1"); jedis.publish("test11", "测试11"); jedis.close(); }
Client1
public static void main(String[] args) { Jedis jedis = new Jedis("10.110.20.152",6379); JedisPubSub jedisPubSub=new JedisPubSub() { /** * 处理普通订阅的频道的消息。 */ @Override public void onMessage(String channel, String message) { System.out.println("TestClient1:channel:"+channel+",message:"+message); } }; //执行完subscribe,本线程会阻塞。 //订阅两个频道:china.beijing和china.shanghai //当订阅的频道有消息时,会执行jedisPubSub的onMessage方法。 jedis.subscribe(jedisPubSub,"china.beijing","china.shanghai"); System.out.println("该行代码是执行不到的"); }
输出结果:
TestClient1:channel:china.beijing,message:中国北京
Client2
public static void main(String[] args) { Jedis jedis = new Jedis("10.110.20.152",6379); JedisPubSub jedisPubSub=new JedisPubSub() { /** * 处理普通订阅的频道的消息。 */ @Override public void onMessage(String channel, String message) { System.out.println("TestClient2:channel:"+channel+",message:"+message); } /** * 取得模式匹配订阅的频道消息。 */ @Override public void onPMessage(String pattern, String channel, String message) { System.out.println("TestClient2:pattern:"+pattern+",channel:"+channel+",message:"+message); } }; //执行完psubscribe,本线程会阻塞。 //订阅三个频道模式:所有以china.做为前缀的频道 + 所有以test做为前缀并且test后只有一个字符的频道 + 频道test11。 //当订阅的频道有消息时,会执行jedisPubSub的onPMessage方法。 jedis.psubscribe(jedisPubSub,"china.*","test?","test11"); System.out.println("该行代码是执行不到的"); }
输出结果:
TestClient2:pattern:china.*,channel:china.beijing,message:中国北京
TestClient2:pattern:china.*,channel:china.jinan,message:中国济南
TestClient2:pattern:test?,channel:test1,message:测试1
TestClient2:pattern:test11,channel:test11,message:测试11