类似的我们再写一个拦截器ProducerInterceptorAnalysis2。两个拦截器的作用都是在发送前添加前缀
@Override
public ProducerRecord<String, String> onSend(ProducerRecord<String, String> record) {
String modifiedValue = "th-" + record.value();
return new ProducerRecord<>(record.topic(), record.partition(), record.timestamp(), record.key(), modifiedValue,
record.headers());
}
@Override
public void close() {
System.out.println("[INFO] 拦截器B CLOSED");
}
修改配置文件的最后一行,多个拦截器之间以逗号隔开
properties.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG,
ProducerInterceptorAnalysis.class.getName() + "," + ProducerInterceptorAnalysis2.class.getName());
先观察效果
很明显,调用顺序 A > B, 关闭顺序 B > A,这与Springmvc是一致的。接下来看看kafka是如何实现的.在org.apache.kafka.clients.producer.internals下的ProducerInterceptors.class中打断点走一下流程,其他几个方法也差不多,都是利用迭代器。
private final List<ProducerInterceptor<K, V>> interceptors;
public ProducerRecord<K, V> onSend(ProducerRecord<K, V> record) {
ProducerRecord<K, V> interceptRecord = record;
Iterator var3 = this.interceptors.iterator();
while(var3.hasNext()) {
ProducerInterceptor interceptor = (ProducerInterceptor)var3.next();
try {
interceptRecord = interceptor.onSend(interceptRecord);
} catch (Exception var6) {
if (record != null) {
log.warn("Error executing interceptor onSend callback for topic: {}, partition: {}", new Object[]{record.topic(), record.partition(), var6});
} else {
log.warn("Error executing interceptor onSend callback", var6);
}
}
}
return interceptRecord;
}
再看一下在producer中拦截器的调用时机
public Future<RecordMetadata> send(ProducerRecord<K, V> record) {
return this.send(record, (Callback)null);
}
public Future<RecordMetadata> send(ProducerRecord<K, V> record, Callback callback) {
//interceptors的类型是ProducerInterceptors,onSend()会链式执行所有拦截器的onSend()方法
ProducerRecord<K, V> interceptedRecord = this.interceptors.onSend(record);
return this.doSend(interceptedRecord, callback);
}