生产者拦截器可以对消息进行预处理。分析下KafkaProducer的拦截器相关源码
调用KafkaProduer的send方法时候第一步就是拦截器对消息进行处理:
public Future<RecordMetadata> send(ProducerRecord<K, V> record, Callback callback) {
//拦截器处理
ProducerRecord<K, V> interceptedRecord = this.interceptors.onSend(record);
//发送消息后续操作
return doSend(interceptedRecord, callback);
}
在KafkaProduer实例化时机读取配置中的interceptor.classes获取配置的拦截器组。然后使用ProducerInterceptors进行包装
//KafkaProduer核心构造方法 忽略无关代码
//...
List<ProducerInterceptor<K, V>> interceptorList = (List)(new ProducerConfig(userProvidedConfigs, false))
.getConfiguredInstances(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, ProducerInterceptor.class);
//初始化拦截器
this.interceptors = new ProducerInterceptors<>(interceptorList);
//...
默认值初始化是个空集合:
properties.put("interceptor.classes", "全类名");
interceptor.classes从源码配置找到:
properties.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, "全类名");
/**
初始化源码:
.define(INTERCEPTOR_CLASSES_CONFIG,Type.LIST,Collections.emptyList()....
这里的全类名在源码中初始化的时候是一个配置list类型,
在KafkaProducer核心的构造方法中:也就是实例化KafkaProducer会读取自定义的拦截器集合。
*/
ProducerInterceptors 拦截器容器,持有一组拦截器链 List
拦截器是有顺序的,就是配置顺序
onSend(),方法就是按照配置顺序依次执行每个自定义拦截器重写的onsend方法,这个方法,如果有中途的拦截器抛出异常,那就继续执行下一个拦截器进行处理,该拦截器失效。
onAcknowledgement(),就是收到ack的回调方法,每个拦截器都会执行,
onSendError(),发送失败的回调方法,每个拦截器都会
自定义拦截器的onAcknowledgement方法先于callback被调用见
博客5-1 2.2分析
ProducerInterceptor
//拦截器执行的方法
public ProducerRecord<K, V> onSend(ProducerRecord<K, V> record);
//当收到ack或者发送失败异常将会被调用
//类似于send方法的callback,但是先于callback被调用
//这个方法execute in the background I/O thread ,所以尽量不要使用什么复杂或者耗时操作,
//避免性能损耗
public void onAcknowledgement(RecordMetadata metadata, Exception exception);
public ProducerRecord<K, V> onSend(ProducerRecord<K, V> record) {
ProducerRecord<K, V> interceptRecord = record;
//遍历interceptors中的拦截器,依次执行onSend方法,默认没有拦截器,for内部不执行
for (ProducerInterceptor<K, V> interceptor : this.interceptors) {
try {
//如果有中途的拦截器抛出异常,那就继续执行下一个拦截器进行处理,该拦截器作用失效。
interceptRecord = interceptor.onSend(interceptRecord);
} catch (Exception e) {
// do not propagate interceptor exception, log and continue calling other interceptors
// be careful not to throw exception from here
if (record != null)
log.warn("Error executing interceptor onSend callback for topic: {}, partition: {}", record.topic(),
record.partition(), e);
else
log.warn("Error executing interceptor onSend callback", e);
}
}
return interceptRecord;
}
n(“Error executing interceptor onSend callback”, e);
}
}
return interceptRecord;
}