簡體   English   中英

使用 Spring Kafka 從單個主題反序列化不同的消息(使用共享數據)

[英]Deserializing different messages (With shared data) from single topic with Spring Kafka

TL;DR如何使用@KafkaListener@KafkaHandler根據屬性將一個主題映射到不同的處理程序,映射到具體對象?

細節:

我有一個主題,其中包含不同的消息。 消息格式為

{type: 1, data1:"foo"}
{type: 2, data2:"bar"}

我最好像這樣通過單個偵聽器使用它們

// Irrelevant code ommited
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
        @JsonSubTypes.Type(value = Type1Pojo.class),
        @JsonSubTypes.Type(value = Type2Pojo.class)
})
abstract class BasePojo {int type;}
@JsonTypeName("1")
class Type1Pojo extends BasePojo {}
@JsonTypeName("2")
class Type2Pojo extends BasePojo {}

@KafkaListener(containerFactory = "containerFactory")
class Listener {
    @KafkaHandler
    public void handle(Type1Pojo obj, final ConsumerRecordMetadata metadata);

    @KafkaHandler
    public void handle(Type2Pojo obj, final ConsumerRecordMetadata metadata);
}

使用以下配置

    @Bean
    public JsonDeserializer<BasePojo> jsonDeserializer(ObjectMapper objectMapper) {
        var jsonDeserializer = new JsonDeserializer<BasePojo>(objectMapper);
        // Without this, JsonDeserializer@543 aka 'public T deserialize(String topic, @Nullable byte[] data)'
        // would fail the assertion @554->No headers available and no default type provided
        jsonDeserializer.setTypeResolver((topic, data, headers) -> objectMapper.constructType(BasePojo.class));
        return jsonDeserializer;
    }

    @Bean
    public ConsumerFactory<String, BasePojo> consumerFactory(KafkaProperties kafkaProperties, JsonDeserializer<BasePojo> jsonDeserializer) {
        var consumerProperties = kafkaProperties.buildConsumerProperties();
        var kafkaConsumerFactory = new DefaultKafkaConsumerFactory<String, BasePojo>(consumerProperties);
        kafkaConsumerFactory.setValueDeserializer(jsonDeserializer);
        return kafkaConsumerFactory;
    }

    @Bean
    public KafkaListenerContainerFactory<ConcurrentMessageListenerContainer<String, BasePojo>> containerFactory(ConsumerFactory<String, BasePojo> consumerFactory) {
        var kafkaListenerContainerFactory = new ConcurrentKafkaListenerContainerFactory<String, BasePojo>();
        kafkaListenerContainerFactory.setConsumerFactory(consumerFactory);
        return kafkaListenerContainerFactory;
    }

但現在的錯誤是Could not resolve method parameter at ... : No suitable resolver這是我無法解決的問題 - JsonSubtype 都不起作用(盡管 ObjectMapper 正確映射了具體類)和我可憐的 TypeResolver(它解析類正確)。

引發此異常的InvocableHandlerMethod將消息視為GenericMessage [payload=Type1Pojo]所以它不像沒有傳遞正確的類......

版本:

spring-kafka:2.7.6
spring-boot-starter:2.5.4

通過測試容器測試

我實際上還沒有嘗試過這個,但我認為type參數應該是一個string而不是一個int並且你在@JsonSubTypes.Type中缺少name參數

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
        @JsonSubTypes.Type(value = Type1Pojo.class, name = "1"),
        @JsonSubTypes.Type(value = Type2Pojo.class, name = "2")
})
abstract class BasePojo {String type;}
@JsonTypeName("1")
class Type1Pojo extends BasePojo {}
@JsonTypeName("2")
class Type2Pojo extends BasePojo {}

你的數據應該是

{type: "1", data1:"foo"}
{type: "2", data2:"bar"}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM