我在Spring Kafka设置中使用了Avro和Schema注册表。
我想以某种方式处理SerializationException
,它可能会在反序列化期间抛出。
我发现了以下两个资源:
https://github.com/spring-projects/spring-kafka/issues/164
How do I configure spring-kafka to ignore messages in the wrong format?
这些资源建议我在反序列化并监听SerializationException
时返回null而不是抛出KafkaNull
。此解决方案效果很好。
但是,我希望能够引发异常而不是返回null。
KIP-161和KIP-210提供了更好的功能来处理异常。我确实在Spring Cloud中找到了一些提及KIP-161的资源,但是关于Spring-Kafka的内容并没有具体说明。
有人知道如何在Spring Boot中捕获SerializationException
吗?
我正在使用Spring Boot 2.0.2
编辑:我找到了解决方法。
我宁愿抛出异常并捕获它,而不必返回null或KafkaNull
。我在多个不同的项目中使用了自定义的Avro序列化器和反序列化器,其中一些不是Spring。如果我更改了Avro序列化器和解串器,则需要更改其他一些项目,以期望解串器返回null。
我想关闭容器,以免丢失任何消息。生产中永远不应期望SerializationException。只有在架构注册表关闭或以某种方式将未格式化的消息发送到生产kafka时,才应该发生SerializationException。无论哪种方式,SerializationException都应该很少发生,如果发生这种情况,那么我想关闭容器,这样就不会丢失任何消息,并且我可以调查问题。
只需考虑将捕获您的使用者容器中的所有异常。在我的特定情况下,我只想关闭SerializationException
public class SerializationExceptionHandler extends ContainerStoppingErrorHandler {
@Override
public void handle(Exception thrownException, List<ConsumerRecord<?, ?>> records, Consumer<?, ?> consumer,
MessageListenerContainer container) {
//Only call super if the exception is SerializationException
if (thrownException instanceof SerializationException) {
//This will shutdown the container.
super.handle(thrownException, records, consumer, container);
} else {
//Wrap and re-throw the exception
throw new KafkaException("Kafka Consumer Container Error", thrownException);
}
}
}
此处理程序将传递到使用者容器。下面是一个例子
KafkaListenerContainerFactory
bean。
@Bean
public KafkaListenerContainerFactory<ConcurrentMessageListenerContainer<Integer, String>>
kafkaListenerContainerFactory(JpaTransactionManager jpa, KafkaTransactionManager<?, ?> kafka) {
ConcurrentKafkaListenerContainerFactory<Integer, String> factory =
new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory());
factory.setConcurrency(1);
factory.getContainerProperties().setPollTimeout(3000);
factory.getContainerProperties().setErrorHandler(new SerializationExceptionHandler());
factory.getContainerProperties().setTransactionManager(chainedTxM(jpa, kafka));
return factory;
}
答案 0 :(得分:5)
Spring无能为力;反序列化发生在使用者获取任何数据之前。您需要增强解串器。
但是我希望能够引发异常而不是返回null。
这无济于事,因为Kafka不知道如何处理该异常。再次;这些都是在数据可用之前发生的,因此返回null(或其他一些特殊值)是最好的技术。
编辑
在2.2中,我们添加了一个error handling deserializer,它委托给实际的反序列化器并返回null,但标头中除外;然后,侦听器容器会将其直接传递给错误处理程序,而不是侦听器。