关于使用WebSocket时无法使用@Autowired 注入的问题
目录
根本原因:WebSocket 类不是由 Spring 管理的 Bean 实例
解决方案:手动从 Spring 容器中获取 Bean
1. 创建 Spring 上下文工具类:
2. 在 WebSocket 中使用:
虽然加上了 @Component
,但 在 WebSocket 的生命周期回调方法中使用 @Autowired
注入其他 Bean 时会失败,这是因为:
根本原因:WebSocket 类不是由 Spring 管理的 Bean 实例
尽管你加了 @Component
,Spring 确实会把这个类作为一个 Bean 注册到容器中。但是,Java 的 WebSocket API(JSR-356)在创建 @ServerEndpoint
对应的类实例时,并不是通过 Spring 容器来创建的,而是由底层的 WebSocket 容器(如 Tomcat、Jetty)直接 new 出来的。
也就是说:
- Spring 创建了一个
WebSocketServer
实例(作为 Bean) - WebSocket 容器又自己 new 了一个
WebSocketServer
实例(用于处理连接) - 这个 new 出来的实例并没有被 Spring 管理,所以里面的
@Autowired
字段是 null
@Component
@ServerEndpoint("/webSocket/{userId}")
public class WebSocketServer {@Autowiredprivate SomeService someService; // 会是 null@OnOpenpublic void onOpen(...) {someService.doSomething(); // NullPointerException!}
}
解决方案:手动从 Spring 容器中获取 Bean
你可以通过一个工具类,从 Spring 容器中手动获取你需要的 Bean。
1. 创建 Spring 上下文工具类:
@Component
public class SpringContextUtils implements ApplicationContextAware {private static ApplicationContext context;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) {context = applicationContext;}public static <T> T getBean(Class<T> beanClass) {return context.getBean(beanClass);}public static <T> T getBean(String name, Class<T> beanClass) {return context.getBean(name, beanClass);}
}
2. 在 WebSocket 中使用:
@Component
@ServerEndpoint("/webSocket/{userId}")
public class WebSocketServer {@OnOpenpublic void onOpen(Session session, @PathParam("userId") String userId) {SomeService someService = SpringContextUtils.getBean(SomeService.class);someService.doSomething();}
}