java sub_java实现Pub/Sub

jedis 实现Pub/Sub

redis支持的Pub/Sub消息模式,类似JMS的“topic” 功能,但是这些消息不支持持久化,而且redis的订阅端需要独占链接,消息接收将是阻塞的。

Redis 的消息即发即失,sever不会保存消息,如果publish 的消息没有任何client 处于subscribe状态,消息将会丢失,如果client在subscribe时,链接断开后重连,消息将会丢失。

jedis 实现Pub/Sub

引入jedis-client jar包

redis.clients

jedis

${jedis.version}

使用Spring 来配置jedis 连接池和RedisUtil的注入。(spring-redis.xml )

创建一个订阅者

要使用Jedis的pub/sub功能,订阅者必须实现JedisPubSub 自己的方法,功能如下:

/** * 处理消息即接收推送消息体 * *@param channel * 订阅频道 *@param message * 订阅的消息体 *@author zhy *@date 2016年5月26日 */

public class Subscriber extends JedisPubSub {

private static final Logger logger = Logger.getLogger(JedisMessageListener.class);

private JpushMessageService jpushMessageService;

@Override

public void onMessage(String channel, String message) {

ApplicationContext context = SpringContextUtil.getApplicationContext();

jpushMessageService = (JpushMessageService) context.getBean("jpushMessageService");

logger.info("Received subscribed message: " + message);

try {

List obdId = new ArrayList<>();

obdId.add("101d85590947c721b38");

obdId.add("1a1018970aa69c0328f");

int li = message.indexOf("-");

String realMessage = message.substring(li + 1);

logger.info("what is real message is <>");

String msgContent = "【嘉禾影城】" + realMessage;

String topic = "小提醒";

// 发送推送消息

boolean flag = jpushMessageService.sendCustomMessage(obdId, topic, msgContent);

if (!flag) {

logger.error("save registrationInfo failed! regInfo=" + msgContent);

}

} catch (Exception e) {

logger.error("Handle message failed!message=" + message, e);

}

}

@Override

public void onPMessage(String pattern, String channel, String message) {

logger.info(String.format("PMessage. Pattern: %s, Channel: %s, Msg: %s", pattern, channel, message));

}

@Override

public void onSubscribe(String channel, int subscribedChannels) {

logger.info("onSubscribe");

}

@Override

public void onUnsubscribe(String channel, int subscribedChannels) {

logger.info("onUnsubscribe");

}

@Override

public void onPUnsubscribe(String pattern, int subscribedChannels) {

logger.info("onPUnsubscribe");

}

@Override

public void onPSubscribe(String pattern, int subscribedChannels) {

logger.info("onPSubscribe");

}

}

启动一个发布者,只需要调用Jedis的publish 方法即可。

/** * 发布者 * *@author zhy * */

public class Publisher {

private static final Logger LOGGER = Logger.getLogger(Publisher.class);

private Jedis publisherJedis;

private final String channel;

public Publisher(Jedis publisherJedis,String channel){

this.publisherJedis = publisherJedis;

this.channel = channel;

}

public void startPublish(){

LOGGER.info("Read message from channel(quit for terminate)");

try {

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

while (true) {

String message = reader.readLine();

if(!"quit".equals(message)){

publisherJedis.publish(channel, message);

}else{

break;

}

}

} catch (Exception e) {

LOGGER.error("IO failuer while reading input",e);

}

}

}

主程序,首先定义了channel的名字,并获取配置文件中jedisPool 的实例。

/** * 主程序 * *@author zhy * */

public class MainProgram {

private static final Logger LOGGER = Logger.getLogger(MainProgram.class);

private static final String QUEUE_MESSAGE_SUBSCRIBE = "queue:message:subscribe"; //定义channel名字

public static ApplicationContext springContext;

public static void main(String[] args){

// 主要是获取reids连接

springContext = new ClassPathXmlApplicationContext("applicationContext.xml");

final JedisPool jedisPool = (JedisPool) springContext.getBean("jedisPool");

final Subscriber subscriber = new Subscriber();

// 订阅线程:接收消息

new Thread(new Runnable() {

public void run() {

LOGGER.info("Subscribing to \"Mychannel\". This tread will be block !");

//线程进入订阅模式,阻塞

jedisPool.getResource().subscribe(subscriber, QUEUE_MESSAGE_SUBSCRIBE);

//当unsubscribe 方法被调用时,才执行以下代码

LOGGER.info("Subscribtion ended !");

}

}).start();

// 主线程:发布消息到QUEUE_MESSAGE_SUBSCRIBE频道上

new Publisher(jedisPool.getResource(), QUEUE_MESSAGE_SUBSCRIBE).startPublish();

jedisPool.getResource().close();

//unsubscribe

subscriber.unsubscribe();

jedisPool.getResource().close();

}

}

由于消息订阅者比较特殊,需要独占链接,因此在进入订阅状态后会阻塞线程,需要我们为它创建新的线程作为订阅线程,并且用主线程来发布消息,sub()方法将一直被阻塞,直到调用unsubscribe方法才结束。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值