下面的代码使用redis实现订阅/发布。
在redis中可以同时订阅多个频道,如果有消息发布是redis会发出通知。jedis中提供了JedisPubSub抽象类来提供发布/订阅的机制,在实际应用中需要实现JedisPubSub类。
package com.qinying.demo.redis;
import redis.clients.jedis.JedisPubSub;
public class Subscriber extends JedisPubSub {
@Override
public void onMessage(String channel, String message) {
super.onMessage(channel, message);
System.out.println(channel + ":" + message);
}
}
上面的类是从JedisPubSub继承的类,我要用它来订阅一些频道,并获得消息。
main方法如下
package com.qinying.demo.redis;
import org.apache.log4j.Logger;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class Program {
public static final String CHANNEL_NAME = "commonChannel";
public static Logger logger = Logger.getLogger(Program.class);
public static void main(String[] args) {
JedisPoolConfig poolConfig = new JedisPoolConfig();
JedisPool jedisPool = new JedisPool(poolConfig, "10.2.2.206", 6379, 0);
final Jedis subscriberJedis = jedisPool.getResource();
final Subscriber subscriber = new Subscriber();
final Jedis subscriberJedis2 = jedisPool.getResource();
final Subscriber subscriber2 = new Subscriber();
new Thread(new Runnable() {
public void run() {
try {
logger.info("Subscribing to \"commonChannel\". This thread will be blocked.");
subscriberJedis.subscribe(subscriber, CHANNEL_NAME);
logger.info("Subscription ended.");
} catch (Exception e) {
logger.error("Subscribing failed.", e);
}
}
}).start();
new Thread(new Runnable() {
public void run() {
try {
logger.info("Subscribing to \"commonChannel\". This thread will be blocked.");
subscriberJedis2.subscribe(subscriber2, CHANNEL_NAME);
logger.info("Subscription ended.");
} catch (Exception e) {
logger.error("Subscribing failed.", e);
}
}
}).start();
//subscriber.unsubscribe();
//jedisPool.returnResource(subscriberJedis);
}
}
在上面的例子中,我们使用JedisPool来获得Jedis的实例。 Jedis类是非线程安全的,但是JedisPool是线程安全的。我使用了两个Jedis实例,一个用来发布消息,另一个订阅频道。
我在另外一个线程中实现订阅。
下面的类实现发布消息到redis的频道中。
package com.qinying.demo.redis;
import org.apache.log4j.Logger;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class Publisher {
private static final Logger logger = Logger.getLogger(Publisher.class);
public static void main(String[] args) {
JedisPoolConfig poolConfig = new JedisPoolConfig();
JedisPool jedisPool = new JedisPool(poolConfig, "10.2.2.206", 6379, 0);
final Jedis publisherJedis = jedisPool.getResource();
publisherJedis.publish("commonChannel", "hello");
}
}
上面的类获得用户的控制台输入,然后发布到redis channel,当用户键入quit时则退出循环
关键点如下:
- 要在单独的线程中订阅, 因为subscribe会阻塞当前线程的执行。 你可以使用一个PubSub实例来订阅多个Channel
- 注意Jedis实例是非线程安全的
- 当需要创建多个jedis实例时要使用JedisPool类,当使用完jedis对象时要放回JedisPool。