将@JmsListener与多个有效负载类型用于同一目标?

时间:2017-03-07 19:18:33

标签: java spring jms spring-jms

我可以将多种类型的实例写入给定目的地,例如:

JmsTemplate template = ...
Alpha alpha = new Alpha(...);
Beta beta = new Beta(...);

template.convertAndSend("my-destination", alpha);
template.convertAndSend("my-destination", beta);

我以为我能够提供多个@JmsListener带注释的方法来接收不同的消息有效负载 - 如下所示:

@JmsListener(destination = "my-destination")
public void receiveAlpha(Alpha alpha) { ... }

@JmsListener(destination = "my-destination")
public void receiveBeta(Beta beta) { ... }

但是,如果我尝试这样做,我会在PayloadArgumentResolver.resolveArgument中获得例外,因为它无法区分应将Beta值发送到一个方法而将Alpha值发送给另一个方法。

我该如何处理?当我将有效负载类型编码为消息属性时,我可以指定一个选择器来使事情正常工作:

@JmsListener(destination = "my-destination", selector = "_type = 'Alpha'")
public void receiveAlpha(Alpha alpha) { ... }

@JmsListener(destination = "my-destination", selector = "_type = 'Beta'")
public void receiveBeta(Beta beta) { ... }

但是,由于Spring在幕后做了各种各样的聪明,我很惊讶我必须明确地帮助它。

有更隐式/更好的方法吗?

3 个答案:

答案 0 :(得分:3)

JmsListener没有方法支持路由 - 每个带注释的方法都有自己的侦听器容器。

唯一的另一种选择是使用...(Object object)并自己投降。

答案 1 :(得分:1)

尝试在消息后处理器中设置selector属性。在consumer方法中使用与selector相同的属性。请检查此JMSListener selector not working

发送到队列:

    template.convertAndSend("my-destination", alpha, m -> {
        m.setStringProperty("classType", "alpha");
        return m;
    });



从队列中接收消息:

    @JmsListener(destination = "my-destination", selector = "classType = 'alpha'")<br/>
    public void receiveAlpha(Alpha alpha) { ... }

答案 2 :(得分:0)

您可以设置JmsTemplate的消息转换器,以将消息的Java类型设置为消息的“ type”属性,然后在JmsListener中,将选择器配置为仅接收所需的消息类型。

下面是Kotlin中的一个示例,Java应该是相同的

默认消息转换,将消息类型注释为“ type”属性:

@Bean // Serialize message content to json using TextMessage
fun jacksonJmsMessageConverter(): MessageConverter {
    val converter = MappingJackson2MessageConverter()

    converter.setTargetType(MessageType.TEXT)
    converter.setTypeIdPropertyName("type")
    return converter
}

使用带注释的消息转换器,JMS侦听器可以在选择器中指定消息类型:

// Uses default JmsListenerContainerFactory
@JmsListener(destination = "mailbox", containerFactory = "myFactory", selector="type='com.garnetsoft.sf.service.queue.CopyFolderJob'")
fun receiveMessage(job: CopyFolderJob) {
    println("Received copy job <$job>")
}

@JmsListener(destination = "mailbox", containerFactory = "myFactory", selector="type='com.garnetsoft.sf.service.queue.CutFolderJob'")
fun receiveMessage(job: CutFolderJob) {
    println("Received cut job <$job>")
}

希望这会有所帮助。