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;
}