项目中用到了WebSocket,在开发时没有问题,但是部署到测试服务器时却出现了问题。
- 环境信息
- SpringBoot 2.3.1.RELEASE
- Tomcat 9.0
- 异常信息
Caused by: java.lang.IllegalStateException: Failed to register @ServerEndpoint
...
Caused by: javax.websocket.DeploymentException: Multiple Endpoints may not be deployed to the same path [/ws/xxx]
- 代码
@Configuration
public class WebsocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
@Component
@ServerEndpoint(value = "/ws/xxx", encoders = { WsEncoder.class })
public class WebSocket {
@OnOpen
public void onOpen(Session session) {
}
@OnClose
public void onClose() {
}
@OnMessage
public void onMessage(String message, Session session) {
}
@OnError
public void onError(Session session, Throwable error) {
}
}
经过对比分析后,发现开发时的容器是SpringBoot内置Tomcat
,使用ServerEndpointExporter扫描注册ServerEndpoint,而测试服务器的容器是Tomcat
,使用自带jar包中的ServerApplicationConfig扫描注册ServerEndpoint,不同的容器使用不同的扫描机制。所以在开发环境需要注入ServerEndpointExporter,而在测试、生产环境则不需要注入,而是使用Tomcat容器去管理。
- 修改后代码
@ConditionalOnProperty(name = "spring.profiles.active", havingValue = "dev")
@Configuration
public class WebsocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
@ConditionalOnClass(value = WebsocketConfig.class)
@Component
@ServerEndpoint(value = "/ws/{token}", encoders = { WsEncoder.class })
public class WebSocket {
....
}