I'm new to Spring (and asking questions on stackoverflow).
I'd like to start an embedded (Tomcat) server via Spring Boot and register a JSR-356 WebSocket endpoint to it.
This is the main method:
@ComponentScan
@EnableAutoConfiguration
public class Server {
public static void main(String[] args) {
SpringApplication.run(Server.class, args);
}
}
This is how the configuration looks:
@Configuration
public class EndpointConfig {
@Bean
public EchoEndpoint echoEndpoint() {
return new EchoEndpoint();
}
@Bean
public ServerEndpointExporter endpointExporter() {
return new ServerEndpointExporter();
}
}
The EchoEndpoint
implementation is straight-forward:
@ServerEndpoint(value = "/echo", configurator = SpringConfigurator.class)
public class EchoEndpoint {
@OnMessage
public void handleMessage(Session session, String message) throws IOException {
session.getBasicRemote().sendText("echo: " + message);
}
}
For the second part I've followed this blog post: https://spring.io/blog/2013/05/23/spring-framework-4-0-m1-websocket-support.
However, when I run the application I get:
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
The exception is further caused by a NullPointerException
in ServerEndpointExporter
, because the getServletContext
method on the applicationContext
returns still null
at this point.
Can somebody with a better understanding of Spring help me out? Thanks!
Introduction to the WebSocket API in Java EE 7 By maintaining a constant connection, WebSocket provides full-duplex client/server communication. It also provides a low-latency, low-level communication that works on the underlying TCP/IP connection.
You can't call an HTTP API from web socket. You can call a web socket API from a web socket. That mostly means you send some specific message over web socket to the server, and the server sends something specific back.
In order to tell Spring to forward client requests to the endpoint , we need to register the handler. Start the application- Go to http://localhost:8080 Click on start new chat it opens the WebSocket connection. Type text in the textbox and click send. On clicking end chat, the WebSocket connection will be closed.
ServerEndpointExporter
makes some assumptions about the lifecycle of an application context that don't hold true when you're using Spring Boot. Specifically, it's assuming that when setApplicationContext
is called, calling getServletContext
on that ApplicationContext
will return a non-null value.
You can work around the problem by replacing:
@Bean
public ServerEndpointExporter endpointExporter() {
return new ServerEndpointExporter();
}
With:
@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);
}
}
};
}
This defers the processing until the servlet context is available.
Update: You may like to watch SPR-12109. Once it's fixed the workaround described above should no longer be necessary.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With