SpringBoot集成WebSocket--------Spring方式集成(一)

  • 一、引入依赖
  • 二、配置
  • 1、WebSocketConfigurer配置器
  • 2、@EnableWebSocket注解
  • 3、实现WebSocketConfigurer配置
  • 三、注册WebSocketHandler
  • 1、WebSocketHandler消息处理器接口
  • 2、注册WebSocketHandler
  • 四、配置WebSocketHandler
  • 五、WebSocketMessage和WebSocketSession
  • 1、WebSocketMessage
  • 2、WebSocketSession


一、引入依赖

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-websocket</artifactId>
   <version>2.7.0</version>
</dependency>

二、配置

1、WebSocketConfigurer配置器

/**
 *  实现回调方法registerWebSocketHandlers(会被@EnableWebSocket注解获取并回调)配置WebSocket的请求处理逻辑
 */
public interface WebSocketConfigurer {

	/**
	 * 注册WebSocketHandler(WebSocket的核心处理器,可以监听指定端点),也可以设置SockJS回退选项
	 */
	void registerWebSocketHandlers(WebSocketHandlerRegistry registry);、
}

2、@EnableWebSocket注解

(1)注解引入一个配置类DelegatingWebSocketConfiguration.class

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebSocketConfiguration.class)
public @interface EnableWebSocket {
}

(2)DelegatingWebSocketConfiguration配置类会被容器自动加载,同时会注入容器中所有的WebSocketConfigurer实现到configurers中;同时registerWebSocketHandlers()方法会遍历configurers并回调所有WebSocketConfigurer的registerWebSocketHandlers()方法完成WebSocket的核心处理器的配置

@Configuration(proxyBeanMethods = false)
public class DelegatingWebSocketConfiguration extends WebSocketConfigurationSupport {

	private final List<WebSocketConfigurer> configurers = new ArrayList<>();


	@Autowired(required = false)
	public void setConfigurers(List<WebSocketConfigurer> configurers) {
		if (!CollectionUtils.isEmpty(configurers)) {
			this.configurers.addAll(configurers);
		}
	}


	@Override
	protected void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
		for (WebSocketConfigurer configurer : this.configurers) {
			configurer.registerWebSocketHandlers(registry);
		}
	}

}

在父类WebSocketConfigurationSupport中,被@Bean注释的webSocketHandlerMapping()开始初始化时,会从容器中获取一个默认的TaskScheduler(本配置类中使用@Bean注入的),然后通过initHandlerRegistry()创建一个ServletWebSocketHandlerRegistry,在initHandlerRegistry()方法中将创建的ServletWebSocketHandlerRegistry传递给registerWebSocketHandlers(),该方法就是由其子类DelegatingWebSocketConfiguration实现的,在上面的描述中可以看到出DelegatingWebSocketConfiguration 又将ServletWebSocketHandlerRegistry传递给了每一个用户自定义的WebSocketConfigurer的registerWebSocketHandlers()方法,用于配置WebSocketHandler

public class WebSocketConfigurationSupport {

	@Nullable
	private ServletWebSocketHandlerRegistry handlerRegistry;

	@Nullable
	private TaskScheduler scheduler;


	@Bean
	public HandlerMapping webSocketHandlerMapping(@Nullable TaskScheduler defaultSockJsTaskScheduler) {
		ServletWebSocketHandlerRegistry registry = initHandlerRegistry();
		if (registry.requiresTaskScheduler()) {
			TaskScheduler scheduler = defaultSockJsTaskScheduler;
			Assert.notNull(scheduler, "Expected default TaskScheduler bean");
			registry.setTaskScheduler(scheduler);
		}
		return registry.getHandlerMapping();
	}

	private ServletWebSocketHandlerRegistry initHandlerRegistry() {
		if (this.handlerRegistry == null) {
			this.handlerRegistry = new ServletWebSocketHandlerRegistry();
			registerWebSocketHandlers(this.handlerRegistry);
		}
		return this.handlerRegistry;
	}

	protected void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
	}

	@Bean
	@Nullable
	public TaskScheduler defaultSockJsTaskScheduler() {
		if (initHandlerRegistry().requiresTaskScheduler()) {
			ThreadPoolTaskScheduler threadPoolScheduler = new ThreadPoolTaskScheduler();
			threadPoolScheduler.setThreadNamePrefix("SockJS-");
			threadPoolScheduler.setPoolSize(Runtime.getRuntime().availableProcessors());
			threadPoolScheduler.setRemoveOnCancelPolicy(true);
			this.scheduler = threadPoolScheduler;
		}
		return this.scheduler;
	}
}

注意:如果项目其他地方需要使用TaskScheduler ,并且重复配置了一个TaskScheduler ,这里就会冲突

3、实现WebSocketConfigurer配置

我们可以在一个项目中配置多个WebSocketHandler用于处理不同端点的消息(类似Controller接口)

@Configuration
@EnableWebSocket
@ComponentScan(basePackages = "cn.edu1010.websocket.handler", useDefaultFilters = false, includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Component.class))
public class WebSocketConfig implements WebSocketConfigurer {

	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

	}
}

三、注册WebSocketHandler

1、WebSocketHandler消息处理器接口

public interface WebSocketHandler {

    //WebSocket连接建立成功之后调用
	void afterConnectionEstablished(WebSocketSession session) throws Exception;

    //新的WebSocket消息到达时调用
	void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception;

    //处理来自底层的WebSocket的消息传输错误
	void handleTransportError(WebSocketSession session, Throwable exception) throws Exception;

	 //WebSocket连接已被任何一方关闭,或者发生传输错误之后调用
	void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception;

	//是否支持分片消息
	boolean supportsPartialMessages();
}

可以实现WebSocketHandler接口,也可以继承AbstractWebSocketHandler类来创建WebSocketHandler实例

@Component
public class SpringSocketHandle extends AbstractWebSocketHandler {

	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		// TODO Auto-generated method stub
	}

	/**
	 * 文本消息体
	 */
	@Override
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
		// TODO Auto-generated method stub
	}

	/**
	 * 二进制消息体
	 */
	@Override
	protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
		// TODO Auto-generated method stub
	}

	/**
	 * Pong 消息体
	 */
	@Override
	protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception {
		// TODO Auto-generated method stub
	}

	@Override
	public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
		// TODO Auto-generated method stub
	}

	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
		// TODO Auto-generated method stub
	}
}

2、注册WebSocketHandler

在创建的WebSocketConfig中使用WebSocketHandlerRegistry注册SpringSocketHandle,并为其指定端点"/endpoint"。这里需要注意WebSocketHandlerRegistry .addHandler(WebSocketHandler webSocketHandler, String… paths)的第二个参数是一个字符串类型的参数列表,这就说明你可以为多个端点指定同样配置的WebSocketHandler处理

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
	@Autowired
	public SpringSocketHandle springSocketHandle;

	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
	   registry.addHandler(springSocketHandle, "/endpoint");
	}
}

四、配置WebSocketHandler

WebSocketHandlerRegistry.addHandler()方法注册WebSocketHandler之后会返回WebSocketHandlerRegistration用于配置WebSocketHandler

public interface WebSocketHandlerRegistration {
    //继续添加消息处理器
	WebSocketHandlerRegistration addHandler(WebSocketHandler handler, String... paths);
    //添加握手处理器,处理握手事件
	WebSocketHandlerRegistration setHandshakeHandler(HandshakeHandler handshakeHandler);
    //添加握手拦截器,可以在处理握手前和握手后处理一些业务逻辑
	WebSocketHandlerRegistration addInterceptors(HandshakeInterceptor... interceptors);
    //配置允许的浏览器跨源请求类型
	WebSocketHandlerRegistration setAllowedOrigins(String... origins);
    //配置允许的浏览器跨源请求类型
	WebSocketHandlerRegistration setAllowedOriginPatterns(String... originPatterns);
    //允许使用SockJS应急选项
	SockJsServiceRegistration withSockJS();
}

五、WebSocketMessage和WebSocketSession

1、WebSocketMessage

public interface WebSocketMessage<T> {

	/**
	 * 消息载荷
	 */
	T getPayload();

	/**
	 * 消息字节长度
	 */
	int getPayloadLength();

	/**
	 * 当org.springframework.web.socket.WebSocketHandler#supportsPartialMessages()配置允许分片消息时,
	 * 如果当前消息是客户端本次送达消息的最后一部分时,该方法返回true。如果分片消息不可用或是被禁用,放回false
	 */
	boolean isLast();
}

2、WebSocketSession

public interface WebSocketSession extends Closeable {

	/**
	 * 会话标识
	 */
	String getId();

	/**
	 * WebSocket 连接的URI
	 */
	@Nullable
	URI getUri();

	/**
	 * 返回握手请求中使用的Headers
	 */
	HttpHeaders getHandshakeHeaders();

	/**
	 *返回WebSocke会话关联的属性。
	 *在服务端,可以使用org.springframework.web.socket.server.HandshakeInterceptor填充属性
	 *在客户端,可以使用org.springframework.web.socket.client.WebSocketClient的握手方法填充属性
	 */
	Map<String, Object> getAttributes();

	/**
	 * 返回一个包含已验证的用户名称的java.security.Principal实例,如果用户没有验证成功返回null
	 */
	@Nullable
	Principal getPrincipal();

	/**
	 * 返回请求接收方的地址
	 */
	@Nullable
	InetSocketAddress getLocalAddress();

	/**
	 * 返回客户端的地址
	 */
	@Nullable
	InetSocketAddress getRemoteAddress();

	/**
	 *返回约定的子协议,如果没有协议或是协议失败返回null
	 */
	@Nullable
	String getAcceptedProtocol();

	/**
	 * 配置一次接收文本消息最大值
	 */
	void setTextMessageSizeLimit(int messageSizeLimit);

	/**
	 * 获取一次接收文本消息最大值
	 */
	int getTextMessageSizeLimit();

	/**
	 * 配置一次接收二进制消息最大值
	 */
	void setBinaryMessageSizeLimit(int messageSizeLimit);

	/**
	 * 获取一次接收二进制消息最大值
	 */
	int getBinaryMessageSizeLimit();

	/**
	 * 获取约定的扩展
	 */
	List<WebSocketExtension> getExtensions();

	/**
	 * 发送消息,WebSocket会话底层协议不支持并发发送消息,因此发送必须是同步的。
	 * 保证信息发送同步进行,一种方法是使用org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator
	 * 包装WebSocketSession
	 */
	void sendMessage(WebSocketMessage<?> message) throws IOException;

	/**
	 * 底层连接是否打开
	 */
	boolean isOpen();

	/**
	 * 使用状态码1000关闭WebSocket连接
	 */
	@Override
	void close() throws IOException;

	/**
	 * 使用指定状态码WebSocket连接
	 */
	void close(CloseStatus status) throws IOException;
}