解决Springboot的WebSocket组件(即@ServerEndPoint)无法@Autowired的问题

  • Post author:
  • Post category:其他


最近有一个需求,前台使用WebSocket请求后台,后台给其他页面推送数据。

有这样的需求,势必要在我编写的WebSocket层去调用我的Service层去访问数据库,于是我就写出了如下的代码:

@ServerEndpoint(value = "/websocket")
@Component
public class MyWebSocket {

    private static ConcurrentHashMap<String, MyWebSocket> map = new ConcurrentHashMap<>();

    private Session session;

    @Autowired
    private MyService myServiceImpl;

    ....

}

看起来一切都没有问题,但是当我运行的时候,我发现我的myServiceImpl是空!

结果去网上查了一下,发现在@ServerEndPoint中是无法使用@Autowired注入Bean的。

原理大概是这样:

其实在项目启动的时候,这个MyWebSocket已经被注入了这个MyService的Bean,但是WebSocket的特点就是每建立一个连接,会生成一个新的MyWebSocket对象,网上有人分析过源码,也可以理解成new了一个WebSocket,这样当然是不能获得自动注入的对象了。

所以我的解决方案大概就是获取到Spring容器,然后去进行手动注入。

因为新生成的MyWebSocket对象根本不存在与Spring容器中,所以传统的ContextLoader.getCurrentWebApplicationContext()自然也就无法使用。

我用到了ApplicationContextAware来在项目加载时就获得项目的Spring容器。代码如下

@Component
@Lazy(false)
public class MyApplicationContextAware implements ApplicationContextAware {
 
    private static ApplicationContext APPLICATION_CONTEXT;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        APPLICATION_CONTEXT = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return APPLICATION_CONTEXT;
    }
}

这样我们就可以在任何类中去拿到这个类的ApplicationContext

通过这个ApplicationContext我们就可以在新生成一个WebSocket对象时来手动注入Service层了

@ServerEndpoint(value = "/websocket")
@Component
public class MyWebSocket {

    private static ConcurrentHashMap<String, MyWebSocket> map = new ConcurrentHashMap<>();

    private Session session;

    private MyService myServiceImpl = (MyService) MyApplicationContextAware.getApplicationContext().getBean("myServiceImpl");

这样问题就解决了!



版权声明:本文为qq_38182820原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。