【问题标题】:How does Spring Boot know whether MessageMapping specifies a Jms Queue or a Websocket topic?Spring Boot 如何知道 MessageMapping 指定了 Jms Queue 还是 Websocket 主题?
【发布时间】:2018-11-09 21:16:55
【问题描述】:

我有一个控制器 bean,其方法如下:

@MessageMapping("${my.topic}")
public void receiveCommand(Message content) {
    log.info("Received command: " + content);
}

我还将SimpMessagingTemplateJmsMessagingTemplate 注入到这个控制器中。我相信我的 receiveCommand 方法的问题在于 Spring 期望这是 JMS 消息而不是 WebSocket 消息。但是这似乎无法确定,我如何确保此方法对应于 WebSocket 主题而不是 JMS 队列?

我的应用程序使用@EnableJms@EnableWebSocket 进行了注释,并且可以很好地通过STOMP 接收JMS 消息和发送WebSocket 消息,但似乎无法接收WebSocket 消息。

我的Controller上的消息导入如下。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;

我还有另一种使用有效 JmsListener 的方法,所以我想知道这是否被 Spring 在类路径上以某种方式拾取并将 MessageMapping 覆盖为 JMS 队列名称。

@JmsListener(destination = "${my.destination}")
public void receiveMessage(String content) {
   System.out.println("Jms message: " + content); 
}

在运行如下所示的单元测试时,我没有看到任何堆栈跟踪或错误。

@Autowired
private SimpMessagingTemplate websocket;

@Value("${my.topic}")
private String topic;

@Test
public void shouldReceiveCommandMessages() throws IOException {
    URL url = Resources.getResource("command.json");
    String json = Resources.toString(url, Charsets.UTF_8);
    this.websocket.convertAndSend(topic, json);
}

它在一个更大的SpringBootTest 中,用于测试 Jms 发送和接收。

【问题讨论】:

  • 你的问题不清楚; Message 类型取决于 import 语句。 @MessageMappng 不适用于 JMS。您不能有一个同时使用这两种类型的方法。您将需要 2 种方法,其中一种完全限定类型。模板没有区别;它们用于出站消息。
  • 你收到异常了吗?
  • @GaryRussell 我添加了更多细节以尝试使问题更清楚。您能否通过完全限定类型来澄清您的意思?你是说消息类型吗?
  • 我的意思是,如果您在 JmsListener 中明确地侦听 javax.jms.Message,则必须使用包名称来限定其中之一。 >is that Spring is expecting this to be a JMS message - 不;您对消息Message<?> 有正确的导入。所以这不是问题。 @JmsListener 不会干扰。
  • 你猜为什么这个单元测试不会调用receiveCommand?据我所知,应该配置它,以便它们在同一主题上发送和接收,并注入相同的值。似乎也没有在使用带有 STOMP 套接字的 SockJS 的外部 Web ui 上调用此方法,但同样的 UI 能够接收从 SimpMessagingTemplate 发送的消息。

标签: java spring spring-boot websocket spring-jms


【解决方案1】:

SIMP 模板用于向连接的客户端发送数据;要将数据发送到控制器,您应该使用STOMP Client

4.4.6。发送消息

如果您想从应用程序的任何部分向连接的客户端发送消息怎么办?任何应用程序组件都可以向“brokerChannel”发送消息。最简单的方法是注入一个 SimpMessagingTemplate,并使用它来发送消息。通常它应该很容易按类型注入,例如:

4.4.15。 STOMP 客户端

Spring 提供了一个 STOMP over WebSocket 客户端和一个 STOMP over TCP 客户端。

@Controller
class Listener {

    @MessageMapping("/string")
    public void handle(String in) {
        System.out.println("STOMP Received: " + in);
    }

    @JmsListener(destination = "so50614472")
    public void listen(String in) {
        System.out.println("JMS Received: " + in);
    }

}

STOMP Received: foo
JMS Received: bar

【讨论】:

  • 感谢@GaryRussell 这与前缀中的问题相结合,例如/app/foo 调用 MessageMapping("/foo") 为我修复了它。
  • @Gary Russell 我只是想知道 SimpMessagingTemplate 和 JmsMessagingTemplate 是否有任何特殊区别。或者,在任何情况下,如果一个人优先于另一个人。
  • 不要在 cmets 中就旧答案提出新问题。不同之处在于一个是用于发送到 Web 套接字;另一种是发送给 JMS 代理 - 如果您需要更多说明,请提出一个新问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-31
  • 2017-06-24
  • 2011-03-14
  • 2011-03-31
相关资源
最近更新 更多