【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里起到什么作用,我们可以在官方文档里找到答案。

未完待续。。。

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

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

相关推荐
杨哥带你写代码2 小时前
网上商城系统:Spring Boot框架的实现
java·spring boot·后端
camellias_2 小时前
SpringBoot(二十一)SpringBoot自定义CURL请求类
java·spring boot·后端
背水2 小时前
初识Spring
java·后端·spring
晴天飛 雪2 小时前
Spring Boot MySQL 分库分表
spring boot·后端·mysql
weixin_537590452 小时前
《Spring boot从入门到实战》第七章习题答案
数据库·spring boot·后端
AskHarries3 小时前
Spring Cloud Gateway快速入门Demo
java·后端·spring cloud
Qi妙代码3 小时前
MyBatisPlus(Spring Boot版)的基本使用
java·spring boot·后端
宇宙超级勇猛无敌暴龙战神3 小时前
Springboot整合xxl-job
java·spring boot·后端·xxl-job·定时任务
晚睡早起₍˄·͈༝·͈˄*₎◞ ̑̑3 小时前
SpringBoot(五)
java·spring boot·后端