You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 3.1.3下JmsListener泛型容器对象反序列化问题

Spring Boot JMS + ActiveMQ Artemis 抽象事件类型自动反序列化问题

系统背景

我正在构建一个事件驱动系统,由多个通过领域事件通信的服务组成,所有服务均基于Spring Boot 3.1.3,使用ActiveMQ Artemis作为消息中间件。

核心代码定义

我定义了统一各服务行为的接口与通用代码:

interface DomainEvent
data class DomainEventContainer<D : DomainEvent>(
    val event: D,
    val type: DomainEventType,
    val createdBy: DomainEventOrigin,
    val createdAt: Instant
)
fun interface BaseDomainEventProducer<T : DomainEvent> {
    fun produce(event: T): DomainEventContainer<T>?
}
fun interface BaseDomainEventConsumer<T : DomainEvent> {
    fun consume(container: DomainEventContainer<T>)
}

生产者实现

生产者端的核心发送逻辑如下:

fun produce(event: DomainEvent) {
    // some logic here
    val container = DomainEventContainer(event, type, DomainEventOrigin.MY_SERVICE, Instant.now())
    return try {
        log.info("Sending event $container")
        jmsTemplate.convertAndSend(destination, container)
        container
    } catch (e: Exception) {
        log.info("Error during sending event $container ", e)
        null
    }
}

消费者反序列化失败问题

我尝试在消费者端直接接收泛型容器对象:

@JmsListener(destination = "\${random.artemis.queue}")
override fun consume(message: DomainEventContainer<MyCustomDomainEvent>) {
    eventHandler.handle(container.event)
}

但触发Jackson反序列化异常,报错信息如下:

Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of DomainEvent (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information

手动解决方案(繁琐)

目前只能通过手动在每个监听器中处理反序列化逻辑,比如:

方式一:直接处理jakarta.jms.Message

@JmsListener(destination = "\${random.artemis.queue}")
override fun consume(message: Message) {
    val container = objectMapper.readValue(
        message.getBody(String::class.java),
        object : TypeReference<DomainEventContainer<EmploymentRegisteredDomainEvent>>(){})
    eventHandler.handle(container.event)
}

方式二:使用org.springframework.messaging.Message

@JmsListener(destination = "\${random.artemis.queue}")
override fun consume(message: Message<DomainEventContainer<MyCustomDomain>>) {
    val container = message.payload
    eventHandler.handle(container.event)
}

但这种重复逻辑应该由平台统一处理,而非每个监听器都手动编写。

疑问与需求

Spring Boot的RabbitMQ模块可以直接实现自动处理:发送DomainEventContainer<MyCustomDomain>后,消费者可直接通过如下代码接收:

@RabbitListener(queues = ["random.rabbit.queue"])
fun consume(event: DomainEvent<MyCustomDomain>)

为何Spring JMS模块无法实现类似的自动反序列化?是否有对应的配置项可以实现,避免手动重复逻辑?

内容的提问来源于stack exchange,提问作者mr.nothing

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 16:28:10