在 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
問題。