浅析如何使用SimpMessagingTemplate在应用的任意地方将websocket消息发送给客户端及遇到的循环依赖问题解决
最近在做一个web terminal的需求,自己也写了 demo ,使用 websocket + stomp 进行前后端通讯,其中遇到一个问题,就是我的前后端连接正常及 ssh 连接也正常了,但是我需要把 ssh 连接返回的信息,再返回给客户端。了解到使用 SimpMessagingTemplate ,但是在使用过程中却遇到一个循环依赖的问题,所以这里记录一下。
一、SimpMessagingTemplate的作用
1、SimpMessagingTemplate可以在应用的任意地方发送消息。
Spring的SimpMessagingTemplate能够在应用的任何地方发送消息,甚至不必以首先接收一条消息作为前提。使用SimpMessagingTemplate的最简单方式是将它(或者其接口SimpMessageSendingOperations)自动装配到所需的对象中。
2、SimpMessagingTemplate可以为指定的用户发送消息。
SimpMessagingTemplate还提供了convertAndSendToUser()方法。convertAndSendToUser()方法能够让我们给特定用户发送消息。
simpMessageSendingOperations.convertAndSendToUser("1", "/message", "测试convertAndSendToUser");
stomp.subscribe('/users/1/message', function(message){ });
客户端接收一对一消息的主题是"/users/"+usersId+"/message",这里的用户Id可以是一个普通字符串,只要每个客户端都使用自己的Id并且服务器端知道每个用户的Id就行了。
二、如何使用SimpMessagingTemplate将websocket消息发送给客户端
1、引入 websocket 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2、配置registry
@Configuration
@Slf4j
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry ) {
//路径"/web-terminal"被注册为STOMP端点,对外暴露,客户端通过该路径接入WebSocket服务
registry.addEndpoint("web-terminal").setAllowedOrigins("*");
}
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
// 用户可以订阅来自以"/topic"为前缀的消息,客户端只可以订阅这个前缀的主题
config.enableSimpleBroker("/topic/1024");
// 客户端发送过来的消息,需要以"/xterm"为前缀,再经过Broker转发给响应的Controller
config.setApplicationDestinationPrefixes("/xterm");
}
}
3、使用SimpMessagingTemplate将websocket消息发送给客户端
// 注入SimpMessagingTemplate 调用convertAndSend来推送消息
// 1、注入
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
// 2、使用
//如果没有数据来,线程会一直阻塞在这个地方等待数据。
while ((i = inputStream.read(buffer)) != -1) {
System.out.println(new java.lang.String(Arrays.copyOfRange(buffer, 0, i)));
template.convertAndSend("/topic/1024", new String(Arrays.copyOfRange(buffer, 0, i)));
}
三、解决SimpMessagingTemplate循环依赖问题
1、问题背景
在这个类上注入 SocketService,SocketService 里有我们的业务处理,在 SocketService 里我们需要将消息发送给客户端,所以需要注入 SimpMessagingTemplate, 但是一运行就会报错 循环依赖 的问题。
猜测可能是 WebSocketConfig 实现的 WebSocketMessageBrokerConfigurer 里有实现 SimpMessagingTemplate,那么 WebSocketConfig 依赖 SocketService,反过来 SocketService 又依赖 SimpMessagingTemplate,所以导致了循环依赖问题。
2、解决方案
根据 spring 的描述,基于构造器的循环依赖是没法解决的,官方文档都摊牌了,你想让构造器注入支持循环依赖,是不存在的,不如把代码改了。所以解决方法就是可以改造一下代码。
在 Controller 层去注入 SimpMessagingTemplate,然后将其作为参数传给 Service层的 SocketService 里的方法去调用。
// Controller 层注入及传参
@Controller
@AllArgsConstructor
public class SocketController {
private SocketService socketService;
private SimpMessagingTemplate template;
@MessageMapping("/msg")
public void send(WebSSHData webSSHData) {
System.out.println(webSSHData.getOperate());
socketService.handlerMsg(webSSHData, template);
}
}
// Service 层拿到参数去处理
public void handlerMsg(WebSSHData webSSHData, SimpMessagingTemplate template) {
......
connectToSSH(sshConnectInfo, finalWebSSHData, template);
}
// 在 connectToSSH 里使用
template.convertAndSend("/topic/1024", new String(Arrays.copyOfRange(buffer, 0, i)));
这样确实就解决了循环依赖的问题,消息也顺利的发送给了客户端。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2018-07-17 纯css解决div隐藏浏览器原生滚动条,但保留鼠标滚动效果的问题
2017-07-17 浅析webpack之shimming垫片的理解及常见场景和webpack.ProvidePlugin插件的使用
2017-07-17 代码git提交规范CommitLint使用
2017-07-17 浏览器工作原理:浅析浏览器渲染进程 - HTML、CSS和JavaScript是如何变成页面的?(下)