使用带有Spring Boot的Java API for WebSocket(JSR-356)

我是Spring的新手(并在stackoverflow上提问)。

我想通过Spring Boot启动嵌入式(Tomcat)服务器并向其注册JSR-356 WebSocket端点。

这是主要方法:

@ComponentScan @EnableAutoConfiguration public class Server { public static void main(String[] args) { SpringApplication.run(Server.class, args); } } 

这是配置的外观:

 @Configuration public class EndpointConfig { @Bean public EchoEndpoint echoEndpoint() { return new EchoEndpoint(); } @Bean public ServerEndpointExporter endpointExporter() { return new ServerEndpointExporter(); } } 

EchoEndpoint实现很简单:

 @ServerEndpoint(value = "/echo", configurator = SpringConfigurator.class) public class EchoEndpoint { @OnMessage public void handleMessage(Session session, String message) throws IOException { session.getBasicRemote().sendText("echo: " + message); } } 

对于第二部分,我已经关注了这篇博文: https : //spring.io/blog/2013/05/23/spring-framework-4-0-m1-websocket-support 。

但是,当我运行应用程序时,我得到:

 Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'endpointExporter' defined in class path resource [hello/EndpointConfig.class]: Initialization of bean failed; nested exception is java.lang.IllegalStateException: Failed to get javax.websocket.server.ServerContainer via ServletContext attribute 

ServerEndpointExporterNullPointerException进一步导致exception,因为此时applicationContext上的getServletContext方法仍返回null

有更好理解Spring的人可以帮助我吗? 谢谢!

ServerEndpointExporter对应用程序上下文的生命周期做出一些假设,当您使用Spring Boot时,这些假设不成立。 具体来说,假设调用setApplicationContext时,在该ApplicationContext上调用getServletContext将返回一个非null值。

您可以通过替换来解决此问题:

 @Bean public ServerEndpointExporter endpointExporter() { return new ServerEndpointExporter(); } 

附:

 @Bean public ServletContextAware endpointExporterInitializer(final ApplicationContext applicationContext) { return new ServletContextAware() { @Override public void setServletContext(ServletContext servletContext) { ServerEndpointExporter serverEndpointExporter = new ServerEndpointExporter(); serverEndpointExporter.setApplicationContext(applicationContext); try { serverEndpointExporter.afterPropertiesSet(); } catch (Exception e) { throw new RuntimeException(e); } } }; } 

这将延迟处理直到servlet上下文可用。

更新 :您可能希望观看SPR-12109 。 修复后,不再需要上述解决方法。