kafka
發送自定義消息體(集合,自定義對象)
(學習筆記2020.3.25)
前言:
前幾天學習使用
kafka
一直都是使用對象轉換爲json
字符串在發送的,突然想研究下怎麼直接發送自定義(Object)對象。
1. kafka
的生產者序列化
首先我的生產者工廠配置序列化代碼是:
泛型都是<String,Object>
//key與value序列化方式
configs.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
configs.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
發送的消息體類型是:
@Autowired
private KafkaTemplate<String,Object> kafkaTemplate;
//發送集合
kafkaTemplate.send("mykafkaDemo", Arrays.asList("你好","張韶涵"));
1.1 JsonSerializer
這個類,是作爲發送消息體進行序列化發送的, 我們來看看他是怎麼進行序列化的。
debug源碼發現,是將對象序列化爲字節數組進行發送。
2.kafka
的消費者反序列化
首先我的消費者工廠配置序列化代碼是:
泛型都是<String,Object>
DefaultKafkaConsumerFactory<String, Object> DefaultKafkaConsumerFactory
= new DefaultKafkaConsumerFactory<>(properties,new StringDeserializer(),new JsonDeserializer<>());
2.1JsonDeserializer
這個類是作爲將發送的字節數組進行反序列化的。
debug源碼發現,是將字節數組進行反序列化爲對象。
到此發送集合是沒有任何問題
3. 發送自定義對象
定義一個Message對象…然後進行發送。
@Autowired
private KafkaTemplate<String,Object> kafkaTemplate;
kafkaTemplate.send("mykafkaDemo",new Message("張韶涵", "臺灣"));
首先將對象序列化爲數組,沒有任何問題。
將對象進行反序列化時候,報了不可信包錯誤。
Caused by: java.lang.IllegalArgumentException: The class 'com.zhihao.entity.Message' is not in the trusted packages: [java.util, java.lang]. If you believe this class is safe to deserialize, please provide its name. If the serialization is only done by a trusted source, you can also enable trust all (*)
然後通過debug發現是在
DefaultJackson2JavaTypeMapper類中的toJavaType
方法裏面調用getClassIdType
方法出現了異常, 然後繼續深入getClassIdType
方法,發現是在if (!isTrustedPackage(classId))
判斷是否是可信包,返回的結果進入了拋異常。
這裏我們的包名與原本的可信包進行比較,如果是相等就返回true,不相等就返回false, 因爲
(!isTrustedPackage(classId))
進行了取反,如果不相等就返回false就會拋出不可信包異常。
既然知道了結果,就找解決方法,經過
JsonDeserializer
裏面發現有方法addTrustedPackages
可以添加可信包。
然後在消費者工廠配置value序列化
JsonDeserializer
方式進行修改:
JsonDeserializer<Object> objectJsonDeserializer = new JsonDeserializer<>();
//添加可信序列化包
objectJsonDeserializer.addTrustedPackages("com.zhihao.entity");
DefaultKafkaConsumerFactory<String, Object> DefaultKafkaConsumerFactory
= new DefaultKafkaConsumerFactory<>(properties,new StringDeserializer(), objectJsonDeserializer);
然後發現
(!isTrustedPackage(classId))
返回了true,不報錯了,可以正常進行反序列化了。
並可以發現可信包裏面又
java.util
與java.lang
,也叫是說明發送這個2個包下的都可信,可以進行正常反序列化。
並且經過錯誤提示,可以設置爲信任所有包
objectJsonDeserializer.addTrustedPackages("*");
那將不進行可信包循環判斷,直接返回
true
。
4. 映射類型(官方發送自定義消息體):
從2.2版開始,使用JSON時,您現在可以使用前面列表中的屬性來提供類型映射。以前,您必須在序列化器和反序列化器中自定義類型映射器。映射由逗號分隔的
token:className
成對列表組成。在出站時,有效負載的類名將映射到相應的令牌。在入站時,類型標頭中的令牌將映射到相應的類名稱。模板,工廠,消費者工廠與監聽容器的泛型都是
Object
下面的示例創建一組映射:
senderProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
senderProps.put(JsonSerializer.TYPE_MAPPINGS, "user:com.zhihao.User, cat:com.zhihao.Cat");
...
consumerProps.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
consumerProps.put(JsonDeSerializer.TYPE_MAPPINGS, "user:com.zhihao.User, cat:com.zhihao.Cat");
如果使用Spring Boot,則可以在
application.properties
(或yaml)文件中提供這些屬性
1