我正在使用Spring Boot使用Kafka将数据从一个应用程序发送到另一个应用程序。
我的设计使用接口声明要发送的数据:
package domain;
interface Data {
public String getData();
public void setData(String data);
}
制作人
在源应用程序中,我将此接口实现为db Entity。
package persistence;
@Data
class DataEntity implements Data {
private String data; // lombok generates getter/setters
}
添加实体后,我想使用KafkaTemplate将其作为更新发送给Kafka
@Component
class DataPublisher implements ApplicationListener<DataEvent> {
@Autowired private KafkaTemplate<String,Data> template;
// I left out DataEvent which is a straightforward ApplicationEvent override
@EventListener(classes = DataEvent.class)
public void onApplicationEvent(DataEvent event) {
template.send("data", (Data) event.getSource());
}
}
// triggered by this call in a service
eventPublisher.publishEvent(new DataEvent(updatedData));
序列化是通过属性完成的
spring:
kafka:
consumer:
value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
properties.spring.json.value.default.type: domain.Data
查看kafkacat的输出,数据发送正常。
消费者
在接收方,我有
@KafkaListener(topics = "data")
public void dataUpdated(@Payload Data data) {
dataService.updateData(data);
}
结果
原因:java.lang.IllegalArgumentException:类'persistence.DataEntity'不在受信任的程序包中[...]
我很好理解-序列化程序发送一个persistence.DataEntity
对象,但是客户端期望一个domain.Data
对象。但这就是设计的本意。我希望客户端仅了解域包,而不是其persistence
实现。 (作为附带的问题,我在哪里可以看到此类型的标头?它不在编码的json AFAICT中,我缺少什么?)
所以问题是:如何强制Spring JsonDeserializer
发送domain.Data
作为序列化数据类型?
我在序列化程序类中确实找到了TYPE_MAPPING属性,但是它唯一的文档是它“将类型映射添加到类型映射器:'foo:com.Foo,bar:com.Bar'”,而没有”什么都没解释,我找不到示例用法。
编辑:
我确实添加了
spring.kafka.producer.properties.spring.json.type.mapping = domain.Data:persistence.DataEntity
到生产者的属性,但这没有帮助。
答案 0 :(得分:1)
您必须在两侧都提供映射。
但是,您应该使用JsonDeserializer
和BytesDeserializer
(只需将其中一个添加为BytesJsonMessageConverter
,而不是使用@Bean
,Boot会将其连接到容器中工厂)。
那样,框架将自动转换为参数类型。
再次,请参见the documentation。