以前一直只是听说过RxJava,但是直到前一阵公司想使用Netflix的conductor,结果conductor不支持kafka,于是便自己想办法在其中集成了kafka,学习源码后才发现conductor跟消息中间件继承接口中使用到了Rx Java,于是趁此机会将RxJava学习了一下,在此归纳一下所学所得。
原生conductor中并没有集成kafka,但是有集成aws的SQS还有nats这两个消息中间件,于是我们可以很轻松得模仿他们的实现去集成kafka,大概思路如下:
1.通过配置文件将kafka的相关配置进行加载,读入内存,为了简单起见,使用如下代码
System.setProperty("kafka_bootstrap.servers", "xxx:9092");
System.setProperty("kafka_group.id", "test");
System.setProperty("kafka_key.deserializer","org.apache.kafka.common.serialization.StringDeserializer");
System.setProperty("kafka_value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
System.setProperty("kafka_key.serializer","org.apache.kafka.common.serialization.StringSerializer");
System.setProperty("kafka_value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
System.setProperty("kafka_schema.registry.url", "true");
2.创建KAFKAObservableQueue来进行kafka的消费与生产,这里使用到了RxJava,conductor会
@Override
public Observable<Message> observe() {
OnSubscribe<Message> subscriber = getOnSubscribe();
return Observable.create(subscriber);
}
@VisibleForTesting
public OnSubscribe<Message> getOnSubscribe() {
return subscriber -> {
Observable<Long> interval = Observable.interval(pollTimeInMS, TimeUnit.MILLISECONDS);
interval.flatMap((Long x)->{
List<Message> msgs = receiveMessages();//在此处调用kafka消费端poll到消息
return Observable.from(msgs);
}).subscribe(subscriber::onNext, subscriber::onError);
};
}
//实现publish方法来发送消息
@Override
public void publish(List<Message> messages) {
messages.forEach(message -> {
try {
String payload = message.getPayload();
ProducerRecord<String,String> record = new ProducerRecord<>(queueURI,JSONObject.toJSONString(message));
producer.send(record);
logger.info(String.format("Published message to %s: %s", queueURI, payload));
} catch (Exception ex) {
logger.error("Failed to publish message " + message.getPayload() + " to " + queueURI, ex);
throw new RuntimeException(ex);
}
});
}
3.创建自己的KAFKAEventQueueProvider,实现EventQueueProvider接口,在这里我们会读取自己的kafka配置生成对应的消费者和生产者,并且重写getQueue方法来生成KAFKAObservableQueue实例,并将生成的实例丢到queues中,queues是一个map用于缓存已经存在的实例
@Inject
public KAFKAEventQueueProvider(Configuration config) {
logger.info("NATS Event Queue Provider init");
// Init KAFKA API. Handle "kafka_" ways to specify parameters
Properties props = new Properties();
Properties temp = new Properties();
temp.putAll(System.getenv());
temp.putAll(System.getProperties());
temp.forEach((key1, value) -> {
String key = key1.toString();
String val = value.toString();
if (key.startsWith("kafka_")) {
key = key.split("_")[1];
props.put(key, config.getProperty(key, val));
}
});
consumer = new KafkaConsumer<>(props);
producer = new KafkaProducer<>(props);
logger.info("KAFKA Event Queue Provider initialized...");
}
@Override
public ObservableQueue getQueue(String queueURI) {
KAFKAObservableQueue queue = queues.computeIfAbsent(queueURI, q -> new KAFKAObservableQueue(queueURI,consumer,producer));
return queue;
}
RxJava由Observer、Subscriber和Scheduler组成,其中Subscriber会通过subsribe方法订阅Observer,Observer将数据返回到Subscriber进行处理,他们都基于Scheduler进行运行。空外rx java也提供了丰富的操作符,对数据进行链式调用,大大提高可读性。
Rx Java中有3个默认数据通道,分别是onNext, onComplete和onError,分别代表下一条数据,结束和错误