|
20 | 20 | import java.nio.charset.StandardCharsets; |
21 | 21 | import java.time.Instant; |
22 | 22 | import java.util.Collection; |
23 | | -import java.util.Iterator; |
24 | 23 | import java.util.List; |
25 | 24 | import java.util.UUID; |
26 | 25 | import java.util.concurrent.ConcurrentHashMap; |
@@ -92,6 +91,12 @@ public class ReplyingKafkaTemplate<K, V, R> extends KafkaTemplate<K, V> implemen |
92 | 91 | private Function<ProducerRecord<K, V>, CorrelationKey> correlationStrategy = |
93 | 92 | ReplyingKafkaTemplate::defaultCorrelationIdStrategy; |
94 | 93 |
|
| 94 | + private String correlationHeaderName = KafkaHeaders.CORRELATION_ID; |
| 95 | + |
| 96 | + private String replyTopicHeaderName = KafkaHeaders.REPLY_TOPIC; |
| 97 | + |
| 98 | + private String replyPartitionHeaderName = KafkaHeaders.REPLY_PARTITION; |
| 99 | + |
95 | 100 | private volatile boolean running; |
96 | 101 |
|
97 | 102 | private volatile boolean schedulerInitialized; |
@@ -204,6 +209,39 @@ public void setCorrelationIdStrategy(Function<ProducerRecord<K, V>, CorrelationK |
204 | 209 | this.correlationStrategy = correlationStrategy; |
205 | 210 | } |
206 | 211 |
|
| 212 | + /** |
| 213 | + * Set a custom header name for the correlation id. Default |
| 214 | + * {@link KafkaHeaders#CORRELATION_ID}. |
| 215 | + * @param correlationHeaderName the header name. |
| 216 | + * @since 2.3 |
| 217 | + */ |
| 218 | + public void setCorrelationHeaderName(String correlationHeaderName) { |
| 219 | + Assert.notNull(correlationHeaderName, "'correlationHeaderName' cannot be null"); |
| 220 | + this.correlationHeaderName = correlationHeaderName; |
| 221 | + } |
| 222 | + |
| 223 | + /** |
| 224 | + * Set a custom header name for the reply topic. Default |
| 225 | + * {@link KafkaHeaders#REPLY_TOPIC}. |
| 226 | + * @param replyTopicHeaderName the header name. |
| 227 | + * @since 2.3 |
| 228 | + */ |
| 229 | + public void setReplyTopicHeaderName(String replyTopicHeaderName) { |
| 230 | + Assert.notNull(replyTopicHeaderName, "'replyTopicHeaderName' cannot be null"); |
| 231 | + this.replyTopicHeaderName = replyTopicHeaderName; |
| 232 | + } |
| 233 | + |
| 234 | + /** |
| 235 | + * Set a custom header name for the reply partition. Default |
| 236 | + * {@link KafkaHeaders#REPLY_PARTITION}. |
| 237 | + * @param replyPartitionHeaderName the reply partition header name. |
| 238 | + * @since 2.3 |
| 239 | + */ |
| 240 | + public void setReplyPartitionHeaderName(String replyPartitionHeaderName) { |
| 241 | + Assert.notNull(replyPartitionHeaderName, "'replyPartitionHeaderName' cannot be null"); |
| 242 | + this.replyPartitionHeaderName = replyPartitionHeaderName; |
| 243 | + } |
| 244 | + |
207 | 245 | @Override |
208 | 246 | public void afterPropertiesSet() { |
209 | 247 | if (!this.schedulerSet && !this.schedulerInitialized) { |
@@ -249,12 +287,12 @@ public RequestReplyFuture<K, V, R> sendAndReceive(ProducerRecord<K, V> record) { |
249 | 287 | Headers headers = record.headers(); |
250 | 288 | boolean hasReplyTopic = headers.lastHeader(KafkaHeaders.REPLY_TOPIC) != null; |
251 | 289 | if (!hasReplyTopic && this.replyTopic != null) { |
252 | | - headers.add(new RecordHeader(KafkaHeaders.REPLY_TOPIC, this.replyTopic)); |
| 290 | + headers.add(new RecordHeader(this.replyTopicHeaderName, this.replyTopic)); |
253 | 291 | if (this.replyPartition != null) { |
254 | | - headers.add(new RecordHeader(KafkaHeaders.REPLY_PARTITION, this.replyPartition)); |
| 292 | + headers.add(new RecordHeader(this.replyPartitionHeaderName, this.replyPartition)); |
255 | 293 | } |
256 | 294 | } |
257 | | - headers.add(new RecordHeader(KafkaHeaders.CORRELATION_ID, correlationId.getCorrelationId())); |
| 295 | + headers.add(new RecordHeader(this.correlationHeaderName, correlationId.getCorrelationId())); |
258 | 296 | this.logger.debug(() -> "Sending: " + record + WITH_CORRELATION_ID + correlationId); |
259 | 297 | RequestReplyFuture<K, V, R> future = new RequestReplyFuture<>(); |
260 | 298 | this.futures.put(correlationId, future); |
@@ -338,18 +376,15 @@ private static <K, V> CorrelationKey defaultCorrelationIdStrategy( |
338 | 376 | @Override |
339 | 377 | public void onMessage(List<ConsumerRecord<K, R>> data) { |
340 | 378 | data.forEach(record -> { |
341 | | - Iterator<Header> iterator = record.headers().iterator(); |
| 379 | + Header correlationHeader = record.headers().lastHeader(this.correlationHeaderName); |
342 | 380 | CorrelationKey correlationId = null; |
343 | | - while (correlationId == null && iterator.hasNext()) { |
344 | | - Header next = iterator.next(); |
345 | | - if (next.key().equals(KafkaHeaders.CORRELATION_ID)) { |
346 | | - correlationId = new CorrelationKey(next.value()); |
347 | | - } |
| 381 | + if (correlationHeader != null) { |
| 382 | + correlationId = new CorrelationKey(correlationHeader.value()); |
348 | 383 | } |
349 | 384 | if (correlationId == null) { |
350 | 385 | this.logger.error(() -> "No correlationId found in reply: " + record |
351 | 386 | + " - to use request/reply semantics, the responding server must return the correlation id " |
352 | | - + " in the '" + KafkaHeaders.CORRELATION_ID + "' header"); |
| 387 | + + " in the '" + this.correlationHeaderName + "' header"); |
353 | 388 | } |
354 | 389 | else { |
355 | 390 | RequestReplyFuture<K, V, R> future = this.futures.remove(correlationId); |
|
0 commit comments