背景
在使用 Spring Cloud Stream 进行分区操作的时候,发现 partitionKeyExpression
配置成 payload.field
并使用 StreamBridge
发送消息时,报了 SpelEvaluationException: EL1008E 错误。
# 配置获取 Message 对象的哪个字段作为分区 key,如根据订单 id 作为 key 则写成 payload.orderId
spring.cloud.stream.bindings.<channelName>.producer.partitionKeyExpression=payload.orderId
在 Github 上找到了该问题的 issue: Using messageKeyExpression=payload.field
with StreamBridge。
根据 Set default SpEL to configure partition key expression for outbound messages 可以知道在旧版本的 Spring Cloud Stream 中是可以使用 payload.field
的,但在这个 commented 提到在并发的情况下 payload.field
会存在问题,因此不支持使用。
解决方案
先说解决方案,主要有以下两种方式:
-
将
payload.field
方式换为headers.field
,意思是将字段设置到headers
中// 伪代码 MessageBuilder.withPayload(data).setHeader("field", 1).build();
-
报这个错误的根本原因是 Spring Cloud Stream 将
payload
由原来的对象转为了字节数组,可以通过自定义的序列化解决spring.cloud.stream.bindings.<channelName>.producer.use-native-encoding=true spring.cloud.stream.kafka.bindings.<channelName>.producer.configuration.key.serializer=org.apache.kafka.common.serialization.StringSerializer spring.cloud.stream.kafka.bindings.<channelName>.producer.configuration.value.serializer=org.springframework.kafka.support.serializer.JsonSerializer
需要注意的是,以上的序列化配置只针对 Kafka 有效,对于 RabbitMQ 通过追踪它的源码,似乎写死了 org.springframework.amqp.support.converter.SimpleMessageConverter
转换器,不支持自定义配置
public class