自定义Interceptor
对于 producer 而言,interceptor 使得用户在消息发送前以及 producer 回调逻辑前有机会对消息做一些定制化需求,比如修改消息等。同时,producer 允许用户指定多个 interceptor按序作用于同一条消息从而形成一个拦截链(interceptor chain)。Intercetpor 的实现接口org.apache.kafka.clients.producer.ProducerInterceptor,其定义的方法包括:
(1)configure(configs)
获取配置信息和初始化数据时调用。
(2)onSend(ProducerRecord):
该方法封装进 KafkaProducer.send 方法中,用户可以在该方法中对消息做任何操作,但最好保证不要修改消息所属的 topic 和分区
(3)onAcknowledgement(RecordMetadata, Exception):
该方法会在消息从 RecordAccumulator 成功发送到 Kafka Broker 之后,或者在发送过程中失败时调用。并且通常都是在 producer 回调逻辑触发之前。onAcknowledgement 运行在producer 的 IO 线程中,因此不要在该方法放入很重的逻辑,否则会拖慢 producer 的消息发送效率
(4)close:
关闭 interceptor,主要用于执行一些资源清理工作
注意:interceptor 可能被运行在多个线程中,因此在具体实现时用户需要自行确保线程安全
1案例需求:
实现一个简单的双interceptor组成的拦截链。第一个interceptor会在消息发送前将时间戳信息加到消息value的最前部;第二个interceptor会在消息发送后更新成功发送消息数或失败发送消息数。

1,java参考代码,详情见代码内:
My_Interceptor_Timestamp
package com.itwise.kafka.interceptor;
import org.apache.kafka.clients.producer.ProducerInterceptor;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import java.util.Map;
/*
* 自定义拦截器进行接收然后再数据前面添加一个时间戳
* 此拦截器是拦截生产者要发送消息之前
*ProducerRecord 是之前创建的生产者
*
* */
public class My_Interceptor_Timestamp implements ProducerInterceptor<String,String> {
@Override
public ProducerRecord<String, String> onSend(ProducerRecord<String, String> producerRecord) {
// 定义一个字符串,将系统时间戳与要发送的消息拼接起来
String Timestamp_value =System.currentTimeMillis()+"--"+producerRecord.value();
// 重新定义一个 ProducerRecord1(生产者 记录) 与producerRecord 的参数 并将其返回
ProducerRecord<String, String> producerRecord1 = new ProducerRecord<>(
producerRecord.topic(),
producerRecord.partition(),
producerRecord.timestamp(),
producerRecord.key(), Timestamp_value);
return producerRecord1;
}
// ack应答机制
@Override
public void onAcknowledgement(RecordMetadata recordMetadata, Exception e) {
}
@Override
public void close() {
}
@Override
public void configure(Map<String, ?> map) {
}
}
2,自定义拦截器进行条件判断成功了多少条消息
My_Interceptor_ResultCallback
package com.itwise.kafka.interceptor;
import org.apache.kafka.clients.producer.ProducerInterceptor;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import java.util.Map;
/*
* 自定义拦截器进行条件判断成功了多少条消息,失败了多少条消息
* 此拦截器是拦截生产者要发送消息之前
*ProducerRecord 是之前创建的生产者
*
* */
public class My_Interceptor_ResultCallback implements ProducerInterceptor<String,String> {
// 定义参数,统计次数
private int success;
private int fail;
@Override
public ProducerRecord<String, String> onSend(ProducerRecord<String, String> producerRecord) {
// 不用定义也一定要有返回值
return producerRecord;
}
// ack应答机制
@Override
public void onAcknowledgement(RecordMetadata recordMetadata, Exception e) {
if (e==null){
// 成功
success+=1;
}else {
// 失败
fail+=1;
}
}
// 关闭之前返回条数
@Override
public void close() {
System.out.println("发送数据的成功的条数是:"+success);
System.out.println("发送数据的失败的条数是:"+fail);
}
@Override
public void configure(Map<String, ?> map) {
}
}
3,生产者:注意调用两个拦截器的关键代码,其他保持不变
package com.itwise.kafka.interceptor;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
public class My_Interceptor_Producer {
/**
* 链接哪一个topic分区
* 实验的主题是itwise
*/
public static void main(String[] args) {
// 定义参数,通过这个属性对象将参数传递进来
Properties props = new Properties();
// 连接kafka集群
props.put("bootstrap.servers", "node2:9092");
// 应答机制--all(-1)
props.put("acks", "all");
// 重试的次数,重连
props.put("retries", 1);
// 每个批次大小(16k)
props.put("batch.size", 16384);
// 等待时间
props.put("linger.ms",1);
// RecordAccumulator 缓冲区大小 32MB
props.put("buffer.memory", 33554432);
// serializer序列化配置;
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
// !!!!!!添加拦截器!!!! 先定义一个拦截器泛型集合
ArrayList<Object> Interceptor_lists = new ArrayList<>();
Interceptor_lists.add("com.itwise.kafka.interceptor.My_Interceptor_ResultCallback");
Interceptor_lists.add("com.itwise.kafka.interceptor.My_Interceptor_Timestamp");
// 将拦截器与生产者链接 ProducerConfig静态方法,连的是Interceptor_lists集合
props.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG,Interceptor_lists);
// 需要传参数
KafkaProducer<String, String> stringStringKafkaProducer
= new KafkaProducer<String, String>(props);
// 发送消息
//发送消息:
for (int i = 0; i < 2000; i++) {
stringStringKafkaProducer.send(new ProducerRecord<String,String>("itwise","itwise-"+i));
//stringStringKafkaProducer.send(new ProducerRecord<String,String>("itwise",0,null,"itwise->"+i));
/* stringStringKafkaProducer.send(new ProducerRecord<String,String>
("itwise", UUID.randomUUID().toString(),"itwise-->>"+i));*/
}
// 关闭IO流
stringStringKafkaProducer.close();
}
}
4,linux启动消费者
可以看见之前订阅的消息
[itwise@node2 ~]$ kafka-console-consumer.sh -consumer.config /opt/module/kafka_2.11-2.4.1/config/consumer.properties -bootstrap-server node2:9092 --topic itwise
在末尾追加消息:
[itwise@node2 ~]$ kafka-console-consumer.sh --bootstrap-server node2:9092 --topic itwise
5,实验结果:
dule/kafka_2.11-2.4.1/config/consumer.properties -bootstrap-server node2:9092 --topic itwise
在末尾追加消息:
[itwise@node2 ~]$ kafka-console-consumer.sh --bootstrap-server node2:9092 --topic itwise
5,实验结果:

本文介绍了如何在ApacheKafka生产者中使用自定义Interceptor进行消息发送前的操作(如添加时间戳)和发送后的计数跟踪。文章详细解释了ProducerInterceptor接口的方法,并提供了两个示例:My_Interceptor_Timestamp用于添加时间戳,My_Interceptor_ResultCallback用于记录发送成功和失败的消息数。
228

被折叠的 条评论
为什么被折叠?



