kafka發送自定義消息體(集合,自定義對象)(學習筆記2020.3.25)

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源碼發現,是將對象序列化爲字節數組進行發送。

8Xe7EF.png

2.kafka的消費者反序列化

首先我的消費者工廠配置序列化代碼是:

泛型都是<String,Object>

DefaultKafkaConsumerFactory<String, Object> DefaultKafkaConsumerFactory
                = new DefaultKafkaConsumerFactory<>(properties,new StringDeserializer(),new JsonDeserializer<>());

2.1JsonDeserializer

這個類是作爲將發送的字節數組進行反序列化的。

debug源碼發現,是將字節數組進行反序列化爲對象。

8XKUVf.png

到此發送集合是沒有任何問題

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))判斷是否是可信包,返回的結果進入了拋異常。

8X1EFK.png

這裏我們的包名與原本的可信包進行比較,如果是相等就返回true,不相等就返回false, 因爲(!isTrustedPackage(classId))進行了取反,如果不相等就返回false就會拋出不可信包異常。

既然知道了結果,就找解決方法,經過JsonDeserializer裏面發現有方法addTrustedPackages可以添加可信包。

8X3hvQ.png

然後在消費者工廠配置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,不報錯了,可以正常進行反序列化了。

8XGyff.png

並可以發現可信包裏面又java.utiljava.lang,也叫是說明發送這個2個包下的都可信,可以進行正常反序列化。

並且經過錯誤提示,可以設置爲信任所有包objectJsonDeserializer.addTrustedPackages("*");

那將不進行可信包循環判斷,直接返回true

8XYTQU.png

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章