简单实现,参看代码说话:
package yieldbot.storm.spout;
import static backtype.storm.utils.Utils.tuple;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.log4j.Logger;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisPubSub;
import backtype.storm.spout.SpoutOutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.topology.base.BaseRichSpout;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.tuple.Fields;
import backtype.storm.utils.Utils;
public class RedisPubSubSpout extends BaseRichSpout {
static final long serialVersionUID = 737015318988609460L;
static Logger LOG = Logger.getLogger(RedisPubSubSpout.class);
SpoutOutputCollector _collector;
final String host;
final int port;
final String pattern;
LinkedBlockingQueue<String> queue;
JedisPool pool;
public RedisPubSubSpout(String host, int port, String pattern) {
this.host = host;
this.port = port;
this.pattern = pattern;
}
//在这里有一个监控的线程类
class ListenerThread extends Thread {
LinkedBlockingQueue<String> queue;
JedisPool pool;
String pattern;
public ListenerThread(LinkedBlockingQueue<String> queue, JedisPool pool, String pattern) {
this.queue = queue;
this.pool = pool;
this.pattern = pattern;
}
public void run() {
// JedisPubSub 对象去Redis中间去订阅一个数据的通道
JedisPubSub listener = new JedisPubSub() {
@Override
public void onMessage(String channel, String message) {
queue.offer(message);
}
@Override
public void onPMessage(String pattern, String channel, String message) {
queue.offer(message);
}
@Override
public void onPSubscribe(String channel, int subscribedChannels) {
// TODO Auto-generated method stub
}
@Override
public void onPUnsubscribe(String channel, int subscribedChannels) {
// TODO Auto-generated method stub
}
@Override
public void onSubscribe(String channel, int subscribedChannels) {
// TODO Auto-generated method stub
}
@Override
public void onUnsubscribe(String channel, int subscribedChannels) {
// TODO Auto-generated method stub
}
};
// 从池中取得对象
Jedis jedis = pool.getResource();
try {
/**
** listener 一个监听的线程
** pattern 模式
/
jedis.psubscribe(listener, pattern);
} finally {
try
{
pool.returnResource(jedis);
}catch(Eexception e)
{
//有关 pool.returnResource(jedis)的诡异现象请参考
//http://www.tuicool.com/articles/aUra2m
System.out.println("请务必使用try-catch");
}
}
}
};
public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
_collector = collector;、
// 初始化队列,pool,和监控的线程
queue = new LinkedBlockingQueue<String>(1000);
pool = new JedisPool(new JedisPoolConfig(),host,port);
ListenerThread listener = new ListenerThread(queue,pool,pattern);
listener.start();
}
public void close() {
pool.destroy();
}
public void nextTuple() {
// 从队列之中取值的一个过程,在这里判断为空以后,就开始不断的使用Storm发射数据
String ret = queue.poll();
if(ret==null) {
Utils.sleep(50);
} else {
_collector.emit(tuple(ret));
}
}
public void ack(Object msgId) {
// TODO Auto-generated method stub
}
public void fail(Object msgId) {
// TODO Auto-generated method stub
}
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("message"));
}
public boolean isDistributed() {
return false;
}
}
Plus:
如果您对于Java数据结构不熟悉,请参考本ID的博文:
Java【集合类型】 - LinedBolockingQueue 详解。
如果您对于Redis-Clinet : jedis API 使用不够熟悉,还请参看本ID的博文:
Redis【Jedis】 - 基本Api 使用详解
如不透彻,还请自行google ,
Thanks 。