在 WebSocket 类中注入 Bean 看似可行而注入 Bean 报错为null
,通常是由于Spring 的单例管理机制与 WebSocket 多实例创建特性冲突导致的,具体分析如下:
原因分析
- Spring 的单例特性:Spring 默认以单例模式管理 Bean,即一个 Bean 在容器中只创建一次。项目启动时,会初始化一个 WebSocket 实例(非用户连接时),此时 Spring 会为该实例注入 Bean,该实例的 Bean 不会为
null
。 - WebSocket 的多实例创建:当新用户连接时,系统会创建新的 WebSocket 实例。由于 Spring 的单例机制,不会为后续创建的 WebSocket 实例再注入 Bean,导致这些新实例中的 Bean 为
null
。
解决方案
通过ApplicationContext
手动获取 Bean,绕过 Spring 自动注入的单例限制,确保每个 WebSocket 实例能获取到 Bean。步骤如下:
- 创建 Spring 上下文工具类:
import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component;@Component public class SpringContextUtil implements ApplicationContextAware {private static ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {SpringContextUtil.applicationContext = applicationContext;}public static ApplicationContext getApplicationContext() {return applicationContext;}public static <T> T getBean(Class<T> clazz) {return applicationContext.getBean(clazz);} }
- 在 WebSocket 类中手动获取 Bean:
import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import org.springframework.stereotype.Component;@Component @ServerEndpoint("/hot-search-ws") public class WebSocketServerSearch {private HotSearchService hotSearchService;@javax.websocket.OnOpenpublic void onOpen(Session session) {// 手动获取servicehotSearchService = SpringContextUtil.getBean(HotSearchService.class);sendHotSearches(session);}private void sendHotSearches(Session session) {try {if (hotSearchService != null) {List<HotSearch> randomHotSearches = hotSearchService.getRandomHotSearches(5);String hotSearchList = randomHotSearches.stream().map(HotSearch::getText).collect(Collectors.joining("\n"));session.getBasicRemote().sendText(hotSearchList);}} catch (Exception e) {e.printStackTrace();}} }
通过上述方法,每个 WebSocket 实例在需要时主动从 Spring 上下文中获取 Bean,避免因单例注入机制导致的
null
问题。