Spring Websocket 原理

使用示例

例子来自于官网

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

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

    @Bean
    public WebSocketHandler myHandler() {
        return new MyHandler();
    }
}

说明:

  1. WebSocketConfigurer 配置 websocket
  2. WebSocketHandler 处理 websocket 的连接。

WebSocketServletAutoConfiguration

添加了 tomcat 对 websocket 的支持,也就是 WsSci。

源码位置: org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
@ConditionalOnWebApplication(type = Type.SERVLET)
@AutoConfigureBefore(ServletWebServerFactoryAutoConfiguration.class)
public class WebSocketServletAutoConfiguration {

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass({ Tomcat.class, WsSci.class })
	static class TomcatWebSocketConfiguration {

		@Bean
		@ConditionalOnMissingBean(name = "websocketServletWebServerCustomizer")
		TomcatWebSocketServletWebServerCustomizer websocketServletWebServerCustomizer() {
			return new TomcatWebSocketServletWebServerCustomizer();
		}
	}
	...
}

@EnableWebSocket

最关键的配置入口。

源码位置: org.springframework.web.socket.config.annotation.EnableWebSocket

1
2
3
4
// 导入 websocket 配置类, 父类为 WebSocketConfigurationSupport
@Import(DelegatingWebSocketConfiguration.class)
public @interface EnableWebSocket {
}

源码位置: org.springframework.web.socket.config.annotation.WebSocketConfigurationSupport

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public class WebSocketConfigurationSupport {

    // 注册 WebSocketHandlerMapping
	@Bean
	public HandlerMapping webSocketHandlerMapping(@Nullable TaskScheduler defaultSockJsTaskScheduler) {
	    // 初始化 registry
		ServletWebSocketHandlerRegistry registry = initHandlerRegistry();
		...
		// 很重要, 后面继续解析
		return registry.getHandlerMapping();
	}

	private ServletWebSocketHandlerRegistry initHandlerRegistry() {
		if (this.handlerRegistry == null) {
			this.handlerRegistry = new ServletWebSocketHandlerRegistry();
			// 由子类 DelegatingWebSocketConfiguration 来实现
			registerWebSocketHandlers(this.handlerRegistry);
		}
		return this.handlerRegistry;
	}
}

源码位置: org.springframework.web.socket.config.annotation.ServletWebSocketHandlerRegistry#getHandlerMapping

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public AbstractHandlerMapping getHandlerMapping() {
    Map<String, Object> urlMap = new LinkedHashMap<>();
    // 遍历所有的 websocket 的配置
    for (ServletWebSocketHandlerRegistration registration : this.registrations) {
        // HttpRequestHandler 实现类为 WebSocketHttpRequestHandler,负责处理 websocket 请求, 很重要
        MultiValueMap<HttpRequestHandler, String> mappings = registration.getMappings();
        mappings.forEach((httpHandler, patterns) -> {
            for (String pattern : patterns) {
                urlMap.put(pattern, httpHandler);
            }
        });
    }
    // WebSocketHandlerMapping 负责拦截 websocket 的 url,然后由 WebSocketHttpRequestHandler 处理请求
    WebSocketHandlerMapping hm = new WebSocketHandlerMapping();
    hm.setUrlMap(urlMap);
    hm.setOrder(this.order);
    if (this.urlPathHelper != null) {
        hm.setUrlPathHelper(this.urlPathHelper);
    }
    return hm;
}

WebSocketHttpRequestHandler 处理 websocket 请求

源码位置: org.springframework.web.socket.server.support.WebSocketHttpRequestHandler#handleRequest

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Override
public void handleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse)
        throws ServletException, IOException {
    ...
    try {
        ...
        // 执行 HandshakeInterceptor#beforeHandshake 方法
        if (!chain.applyBeforeHandshake(request, response, attributes)) {
            return;
        }
        // 执行 websocket 握手, 最终会调用 TomcatRequestUpgradeStrategy#upgradeInternal
        this.handshakeHandler.doHandshake(request, response, this.wsHandler, attributes);
        // 执行 HandshakeInterceptor#afterHandshake 方法
        chain.applyAfterHandshake(request, response, null);
    }
    catch (HandshakeFailureException ex) {
        failure = ex;
    }
    catch (Exception ex) {
        failure = new HandshakeFailureException("Uncaught failure for request " + request.getURI(), ex);
    }
    finally {
        ...
    }
}
0%