I know there are lot of questions on this topic. I have read the spring boot doc and all of the solutions here. According spring boot doc, @ServerEndpoint
is a Javax annotation and @Autowired
components are spring-boot managed. These two cannot be used together. The solution to this would be to add SpringConfigurator
as configurator of the ServerEndpoint
. When I tried this I do get the following error:
Failed to find the root WebApplicationContext. Was ContextLoaderListener not used?
There is no example in the spring-boot websocket page to use ContextLoaderListener
. How can use ContextLoaderListener
so that components can be injected into @ServerEndpoint
annotated controllers?
The following is my code.
Websocket controller
@ServerEndpoint(value = "/call-stream", configurator = SpringConfigurator.class)
public class CallStreamWebSocketController
{
@Autowired
private IntelligentResponseService responseServiceFacade;
// Other methods
}
Websocket configurations
@Configuration
public class WebSocketConfiguration
{
@Bean
public CallStreamWebSocketController callStreamWebSocketController()
{
return new CallStreamWebSocketController();
}
@Bean
public ServerEndpointExporter serverEndpointExporter()
{
return new ServerEndpointExporter();
}
}
Edit:
This has been tagged as a duplicate of this question. I have tried the solution specified in the answers. The solution is to add SpringConfigurator
as configurator of the @ServerEndpoint
. After adding this I still do get the error mentioned in the details.
After some research I found a way to force spring-boot to inject a component into an externally managed/instantiated class.
1) Add a generic method to your class extending ApplicationContextAware
to return a bean.
@Component
public class SpringContext implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
SpringContext.context = context;
}
public ApplicationContext getApplicationContext() {
return context;
}
// Generic method to return a beanClass
public static <T> T getBean(Class<T> beanClass)
{
return context.getBean(beanClass);
}
}
2) Use this method to initialize the class object you want to be injected
private IntelligentResponseService responseServiceFacade = SpringContext.getBean(IntelligentResponseService.class);
So after the above changes my websocket controller would look like this
@ServerEndpoint(value = "/call-stream", configurator = SpringConfigurator.class)
public class CallStreamWebSocketController
{
private IntelligentResponseService responseServiceFacade = SpringContext.getBean(IntelligentResponseService.class);
// Other methods
}