【Spring源码】WebSocket做推送动作的底层实例

一、前瞻

Ok,开始我们今天的对Spring的【模块阅读】。

那就挑Web里的WebSocket模块 ,先思考下本次阅读的阅读线索

  1. WebSocket在Spring里起到什么作用
  2. 这个模块采用了什么设计模式
  3. 我们都知道WebSocket可以主动推送消息给用户,那做推送动作的底层实例究竟是谁

二、探索

我们先整体看下整个模块的组织机构。

要解决阅读线索3 ,看起来应该从上图里的server模块开始。

找了一圈发现并没有什么线索,那我们就从阅读官方文档这个方向入手。

官方文档表面心跳采用了SckJS协议,所以我们应该从图2里的sockjs模块开始探索。

既然是发送消息给用户,那必定有send的动作,我们在sockjs模块全局搜索下。

我们根据搜索定位到了发送消息的WebSocketSession接口

java 复制代码
	/**
	 * Send a WebSocket message: either {@link TextMessage} or {@link BinaryMessage}.
	 * <p><strong>Note:</strong> The underlying standard WebSocket session (JSR-356) does
	 * not allow concurrent sending. Therefore, sending must be synchronized. To ensure
	 * that, one option is to wrap the {@code WebSocketSession} with the
	 * {@link org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator
	 * ConcurrentWebSocketSessionDecorator}.
	 * @see org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator
	 */
	void sendMessage(WebSocketMessage<?> message) throws IOException;

整体看下该接口的类图,看下是哪些具体的子类对象实现了sendMessage接口。

我们找到了以上链条的sendMessage具体实现:

java 复制代码
	@Override
	public final void sendMessage(WebSocketMessage<?> message) throws IOException {
		Assert.state(!isClosed(), "Cannot send a message when session is closed");
		Assert.isInstanceOf(TextMessage.class, message, "SockJS supports text messages only");
		sendMessageInternal(((TextMessage) message).getPayload());
	}

发现sockjs确实是像官方文档所说的,用户客户端发送心跳给服务器,服务器再使用以上的sendMessageInternal保存心跳。并不是我们要找的阅读线索3。

我们找下WebSocketSession接口 的其他子类链条实现,发现真正发送消息给用户的应该是AbstractWebSocketSession

可以在代码里找到发送各种消息格式的实现。

到这我们就解决了阅读线索3:

推送动作的底层实例究竟是谁

而关于阅读线索2:WebSocket模块采用了什么设计模式 ,我们在AbstractWebSocketHandler发现了以下代码块。

java 复制代码
public abstract class AbstractWebSocketHandler implements WebSocketHandler {

	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
	}

	@Override
	public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
		if (message instanceof TextMessage textMessage) {
			handleTextMessage(session, textMessage);
		}
		else if (message instanceof BinaryMessage binaryMessage) {
			handleBinaryMessage(session, binaryMessage);
		}
		else if (message instanceof PongMessage pongMessage) {
			handlePongMessage(session, pongMessage);
		}
		else {
			throw new IllegalStateException("Unexpected WebSocket message type: " + message);
		}
	}

	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
	}

	protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
	}

	protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception {
	}

	@Override
	public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
	}

	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
	}

	@Override
	public boolean supportsPartialMessages() {
		return false;
	}

}

可以看到handleMessage 方法定义了每个消息格式采用不同的消息处理方法,而这些方法该类并没有实现,而是留给了子类去实现。

也就是说handleMessage 方法定义了模板,而具体实现留给了不同子类。

这其实就是采用了模板方法模式

三、总结

而阅读线索1:WebSocket在Spring里起到什么作用,我们可以在官方文档里找到答案。

未完待续。。。

好了,今天的分享就到这👀。大家能否感受到通过按【模块阅读】这种方式来阅读源码的乐趣呢

创作不易,不妨点赞、收藏、关注支持一下,各位的支持就是我创作的最大动力❤️

相关推荐
2401_857622667 小时前
SpringBoot框架下校园资料库的构建与优化
spring boot·后端·php
2402_857589367 小时前
“衣依”服装销售平台:Spring Boot框架的设计与实现
java·spring boot·后端
哎呦没9 小时前
大学生就业招聘:Spring Boot系统的架构分析
java·spring boot·后端
_.Switch9 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
杨哥带你写代码10 小时前
足球青训俱乐部管理:Spring Boot技术驱动
java·spring boot·后端
AskHarries11 小时前
读《show your work》的一点感悟
后端
A尘埃11 小时前
SpringBoot的数据访问
java·spring boot·后端
yang-230711 小时前
端口冲突的解决方案以及SpringBoot自动检测可用端口demo
java·spring boot·后端
Marst Code11 小时前
(Django)初步使用
后端·python·django
代码之光_198011 小时前
SpringBoot校园资料分享平台:设计与实现
java·spring boot·后端