簡體   English   中英

Spring 啟動 kafka 消息傳遞。 如何簡化處理程序的 dto 映射?

[英]Spring boot kafka messaging. How to simplify dto mapping for handlers?

我已經使用 Kafka 配置了我的 Spring Boot 項目。 我可以接收和發布任何基於字符串的消息。

字符串消息不是處理的最佳方式。 具有將消息從字符串默認轉換為對象的功能會更有用。

實現這個功能我需要將幾乎所有的 Kafka 配置從ymljava (使用屬性)。 ...生產者示例

@Bean
public Map<String, Object> producerConfigs() {
    Map<String, Object> props = new HashMap<>();
    props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
    props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
    props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, AccountSerializer.class);
    return props;
}

@Bean
public ProducerFactory<String, Account> producerFactory() {
    return new DefaultKafkaProducerFactory<>(producerConfigs());
}

@Bean
public KafkaTemplate<String, Account> kafkaTemplate() {
    return new KafkaTemplate<>(producerFactory());
}

該代碼有效,但我接受了簡化。 在最好的情況下,我想優雅地配置yml ,可能是一些 java 更改。 但是以直接方式進行操作時,我將獲得額外的每 3 個 bean 來配置每個kafkaTemplatelistenerFactory

它是否可能簡化未來的配置(我需要更多額外的Serializer器`Deserializer`)? 如何?

聚苯乙烯

我想以與此示例類似的方式配置yml

spring:
  kafka:
    consumer:
      group-id: foo
      auto-offset-reset: earliest
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
    producer:
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.apache.kafka.common.serialization.StringSerializer

app:
  topic:
    foo: foo.t

但我不清楚如何使用不同的 ( De ) Serializer在這里配置消費者\\生產者,將它們映射到指定主題......

似乎我沒有任何機會為同一個偵聽器配置不同的SERIALIZER | DESERIALIZER

但是 id 並不意味着我的問題沒有解決方案。

我對所有對象都使用了繼承,並提供了一個抽象AbstractEvent AbstractEvent一般無用,但它在我的解決方案中使用,例如指定SERIALIZER輸入點 | DESERIALIZER 為了獲取上下文中哪個對象的信息,我使用了自定義標頭。 org.apache.kafka.common.serialization.Deserializer沒有頭參數,但我已經實現了我的DESERIALIZER基於ExtendedDeserializer 這種方式讓我可以訪問標題

via public T deserialize(String topic, Headers headers, byte[] data)

我的解串器示例:

@Slf4j
public class AbstractEventDeserializer<T extends AbstractEvent> implements ExtendedDeserializer<T> {

    private Map<String, Class<T>> mappers = new HashMap<>();

    // default behavior
    @Override
    public T deserialize(String arg0, byte[] devBytes) {
        ObjectMapper mapper = new ObjectMapper();
        T bar = null;
        try {
            bar = (T) mapper.readValue(devBytes, Bar.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bar;
    }

    @Override
    public void close() {
        // TODO Auto-generated method stub
    }

    @Override
    public T deserialize(String topic, Headers headers, byte[] data) {
        log.info("handling...");
        headers.forEach(header -> log.info("   {}: {}", header.key(), getHeaderValueAsString(header)));
        Optional<String> classTypeFromHeader = getClassTypeFromHeader(headers);
        if (classTypeFromHeader.isPresent()) {
            return parseFromJson(data, mappers.get(classTypeFromHeader.get()));
        }
        return deserialize(topic, data);
    }

    private Optional<String> getClassTypeFromHeader(Headers headers) {
        return StreamSupport.stream(headers.headers("X-CLASS-TYPE").spliterator(), false)
                .map(Header::value)
                .map(String::new)
                .findFirst();
    }

    private String getHeaderValueAsString(Header header) {
        return Optional.ofNullable(header.value())
                .map(String::new)
                .orElse(null);
    }

    @Override
    public void configure(Map<String, ?> arg0, boolean arg1) {
        log.info("configuring deserialiser");
        if (arg0.containsKey("mappers")) {
            this.mappers = (Map<String, Class<T>>) arg0.get("mappers");
        }
        arg0.keySet().forEach(key -> log.info("   {}:{}", key, arg0.get(key)));
    }

}

如果您想嘗試工作解決方案,請查看實驗示例

Spring 雲服務可以為消費者提供更好的配置、並發、反序列化和更少的樣板代碼。

   <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-stream-kafka</artifactId>
    </dependency>

水槽樣品

@SpringBootApplication
@EnableBinding(Sink.class)
public class LoggingConsumerApplication {

public static void main(String[] args) {
    SpringApplication.run(LoggingConsumerApplication.class, args);
}

@StreamListener(Sink.INPUT)
public void handle(Person person) {
    System.out.println("Received: " + person);
}

public static class Person {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String toString() {
        return this.name;
    }
}
}

示例配置:

spring:
  cloud:
    stream:
      bindings:
        input:
          destination: <your topic>
          group: <your consumer group>
          consumer:
            headerMode: raw
            partitioned: true
            concurrency: 10
      kafka:
        binder:
          brokers: <Comma seperated list of kafka brokers>

此處提供更多信息https://cloud.spring.io/spring-cloud-stream/

暫無
暫無

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

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