spring boot websocket 配置
開啓websocket
@Confituration
public class MyConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
配置websocket訪問處理
@ServerEndpoint(value = "/websocket/myurl"
@Component
public class WebSocketServer {
@OnOpen
public void open(Session session) {
}
@OnClose
public void onClose() {
}
@OnMesage
public void onMessage(String message, Session session){
}
@OnError
public void onError(Session session, Throwable error){
}
}
部署問題描述
在開發IDE的環境下,進行開發調試,沒有任何問題。
如果工程打包方式爲war,且部署到tomcat下,會產生問題。
...
Caused by: java.lang.IllegalStateException: Failed to register @ServerEndpoint class: class org.yunzhong.websocket.WebSocketServer
...
Caused by: javax.websocket.DeploymentException: Multiple Endpoints may not be deployed to the same path [/websocket/myurl] : existing endpoint was [class org.yunzhong.websocket.WebSocketServer] and new endpoint is [class org.yunzhong.websocket.WebSocketServer]
從異常信息可以看出,是我們寫的WebSocketServer被註冊了兩次。
也就是說tomcat自己也註冊了一次。獨立部署的tomcat和embedded tomcat 有何區別,這裏有待查看文檔。
方案
網上的基本都是在發佈的時候註釋掉ServerEndpointExporter Bean的初始化。但是對於真實的開發場景來說,這個方案只能是臨時方案。
根據Spring的配置理念,應該可以通過條件來判斷是否初始化bean。只需要判斷當前的運行環境爲Embedded還是獨立部署,就能動態判斷加載是否創建ServerEndpointExporter。
我們先來看EmbeddedTomecat初始化的代碼:
...
public class EmbeddedServletContainerAutoConfiguration {
@Configuration
@ConditionalOnClass({Servlet.class, Tomcat.class})
@ConditionalOnMissingBean(value =EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT )
public static class EmbeddedTomcat {
@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory(){
return new TomcatEmbeddedServletContainerFactory();
}
}
}
從條件可以看出,當EmbeddedServletContainerFactory有實例化的bean定義時,纔會初始化TomcatEmbeddedServletContainerFactory。
以此類推,我們在ServerEndpointExporter上添加bean依賴聲明:當 TomcatEmbeddedServletContainerFactory 有實例的時候,才創建ServerEndpointExporter。
@Confituration
public class MyConfig {
@Bean
@ConditionalOnBean(TomcatEmbeddedServletContainerFactory.class)
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}