Spring Kafka@SendTo引发异常:需要KafkaTemplate来支持回复
我正试图得到消费者的结果,根据 基于,只有通过使用Spring Kafka@SendTo引发异常:需要KafkaTemplate来支持回复,spring,spring-boot,apache-kafka,spring-kafka,Spring,Spring Boot,Apache Kafka,Spring Kafka,我正试图得到消费者的结果,根据 基于,只有通过使用@SendTo注释才能做到这一点,因为spring boot“如果上下文中还没有卡夫卡模板,也会自动配置卡夫卡模板。” 但我不能让它工作,我仍然可以 java.lang.IllegalStateException: a KafkaTemplate is required to support replies at org.springframework.util.Assert.state(Assert.java:73) ~[spring
@SendTo
注释才能做到这一点,因为spring boot“如果上下文中还没有卡夫卡模板,也会自动配置卡夫卡模板。”
但我不能让它工作,我仍然可以
java.lang.IllegalStateException: a KafkaTemplate is required to support replies
at org.springframework.util.Assert.state(Assert.java:73) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.kafka.config.MethodKafkaListenerEndpoint.createMessageListener(MethodKafkaListenerEndpoint.java:156)
...
这是我的侦听器方法
@KafkaListener(topics=“t_invoice”)
@发送至(“t_分类账”)
公共列表消费(发票)引发IOException{
//做一些处理
var ledgerCredit=new-LedgerEntry(invoice.getAmount(),“贷方”,0,”;
var-ledgerDebit=new-LedgerEntry(0,”,invoice.getAmount(),“借方”);
返回列表(ledgerCredit、ledgerDebit);
}
我错过了什么
这是我在consumer上唯一的@配置文件。
消费者和生产者是分离的系统(例如,支付系统向卡夫卡开具发票,我的程序是会计系统,它获取数据并创建分类账分录)
@配置
公共级卡夫卡康菲{
@自动连线
私人卡夫卡财产卡夫卡财产;
@豆子
公共消费者工厂消费者工厂(){
var properties=kafkaProperties.buildConsumerProperties();
properties.put(ConsumerConfig.METADATA_MAX_AGE_CONFIG,“600000”);
返回新的默认卡夫卡消费工厂(属性);
}
@豆子
公共KafkaListenerContainerFactory KafkaListenerContainerFactory(){
var factory=新的ConcurrentKafkaListenerContainerFactory();
setConsumerFactory(consumerFactory());
返回工厂;
}
}
application.yml
spring:
kafka:
consumer:
group-id: default-spring-consumer
auto-offset-reset: earliest
试错1
如果在运行期间禁用卡夫卡图,或启用调试,则存在以下错误:
org.apache.kafka.common.errors.SerializationException: Can't convert value of class com.accounting.kafkaconsumer.entity.LedgerEntry to class org.apache.kafka.common.serialization.StringSerializer specified in value.serializer
Caused by: java.lang.ClassCastException: class com.accounting.kafkaconsumer.entity.LedgerEntry cannot be cast to class java.lang.String (com.accounting.kafkaconsumer.entity.LedgerEntry is in unnamed module of loader 'app'; java.lang.String is in module java.base of loader 'bootstrap')
at org.apache.kafka.common.serialization.StringSerializer.serialize(StringSerializer.java:28) ~[kafka-clients-2.0.1.jar:na]
at org.apache.kafka.common.serialization.ExtendedSerializer$Wrapper.serialize(ExtendedSerializer.java:65) ~[kafka-clients-2.0.1.jar:na]
at org.apache.kafka.common.serialization.ExtendedSerializer$Wrapper.serialize(ExtendedSerializer.java:55) ~[kafka-clients-2.0.1.jar:na]
...
试错2
如果禁用Kafkanconfig
并使用此签名(返回字符串),它会工作。但这不是预期的,因为我的配置是在kafkanconfig
@KafkaListener(topics=“t_invoice”)
@发送至(“t_分类账”)
公共字符串消费(发票)引发IOException{
//做一些处理
var listLedger=List.of(ledgerCredit,ledgerDebit);
返回objectMapper.writeValueAsString(listLedger);
}
我认为问题在这里(kafkanconfig
),因为我创建了KafkaListenerContainerFactory
的新实例,replyTemplate
为空。
如何正确设置我的kafkanconfig
@Bean
公共KafkaListenerContainerFactory KafkaListenerContainerFactory(){
var factory=新的ConcurrentKafkaListenerContainerFactory();
setConsumerFactory(consumerFactory());
返回工厂;
}
如果覆盖Boot的自动配置容器工厂,那么它将不会。。。自动配置,包括应用模板。定义自己的工厂时,您负责对其进行配置。不清楚为什么要覆盖Boot的kafkaListenerContainerFactory
bean,因为您所做的只是注入消费者工厂。只需删除该@Bean
并使用Boot。如果覆盖Boot的kafkaListenerContainerFactory
请确保设置了回复模板
@Bean
public ConcurrentKafkaListenerContainerFactory<String, Object> kafkaListenerContainerFactory(KafkaTemplate<String, Object> kafkaTemplate) {
ConcurrentKafkaListenerContainerFactory<String, Object> factory =
new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory());
factory.setReplyTemplate(kafkaTemplate); // <============
return factory;
}
@Bean
公共并发kafkaListenerContainerFactory kafkaListenerContainerFactory(KafkatTemplate KafkatTemplate){
ConcurrentKafkalistener集装箱工厂=
新的ConcurrentKafkaListenerContainerFactory();
setConsumerFactory(consumerFactory());
factory.setReplyTemplate(kafkaTemplate);//您使用的是哪个版本的Spring Boot?2.1.6.RELEASE。也使用了2.1.5.RELEASE进行了尝试,但都不起作用。更新了关于问题@GaryRussellSo的完整堆栈跟踪和build.gradle文件,还有一些其他问题。请使用--debug运行并检查自动配置报告。还可以尝试进入容器工厂bean定义。如果您不能找出答案,编辑问题以显示所有@Configuration类和属性。出现了一些尝试性错误(我更新了问题),但仍然没有得到令人满意的结果。当然,如果您覆盖Boot的自动配置容器工厂,那么它将不会…自动配置,包括应用模板。当您定义自己的工厂时,您负责对其进行配置。不清楚为什么要覆盖Boot的kafkaListenerContainerFactory
bean因为你所做的就是注入消费者工厂。只需删除@Bean
并使用Boot。我的错是,获取一些复制粘贴代码来覆盖KafkListenerContainerFactory
Bean。谢谢你Garyin,如果我有一个生产者配置,有一个KafkCamessageListenerContainer和一个ConcurrentKafkListenerContainerFactory,both使用consumer properties“ConsumerConfig”工厂的配置,在任何请求下,my Replying KafkatTemplate都会获得kafka回复超时,例外情况是不要对旧答案提出新问题;如果不查看您的设置,就无法推测问题。提出显示代码和配置的新问题。