在非Spring管理對(duì)象中注入Spring Bean的解決方案
一、教程引言
在 Spring Boot 開發(fā)中,我們習(xí)慣了通過@Autowired/@Resource等注解輕松注入依賴 Bean,但在 WebSocket、定時(shí)任務(wù)、第三方框架實(shí)例化對(duì)象等場景下,會(huì)遇到一個(gè)核心問題:非 Spring 創(chuàng)建的對(duì)象無法直接注入 Spring Bean。
本教程將拆解這一問題的底層邏輯,并講解一種經(jīng)典的解決方案 ——「借殼注入 + 靜態(tài)共享」,幫助你理解其核心原理并掌握實(shí)戰(zhàn)用法
二、核心問題剖析
1. 場景再現(xiàn):WebSocket 無法注入 Bean
當(dāng)使用 WebSocket 時(shí),其實(shí)例通常由 Tomcat/Jetty 等容器通過new關(guān)鍵字創(chuàng)建(而非 Spring),此時(shí)直接在 WebSocketServer 中注入 Mapper/Service 會(huì)失敗:
// 錯(cuò)誤示例:非Spring創(chuàng)建的實(shí)例無法注入Bean
public class WebSocketServer {
// 運(yùn)行時(shí)會(huì)報(bào)空指針:Spring不會(huì)給new出來的對(duì)象注入依賴
@Autowired
private UserMapper userMapper;
// WebSocket核心方法,由框架調(diào)用
public void onMessage(String msg) {
// userMapper為null,拋出NullPointerException
userMapper.insertMessage(msg);
}
}2. 問題根源:兩個(gè)核心規(guī)則
要解決問題,必須先理解 Spring 和 Java 的兩個(gè)底層規(guī)則(核心概念):
| 核心概念 | 規(guī)則描述 | 通俗類比 |
|---|---|---|
| Spring Bean 訪問權(quán)限 | 只有 Spring 自己創(chuàng)建的對(duì)象(標(biāo)注 @Component/@Service 等),才能通過 @Autowired 獲取容器內(nèi)的 Bean | 公司后勤部只給正式員工(Spring 創(chuàng)建的對(duì)象)發(fā)門禁卡(Bean) |
| 靜態(tài)變量類級(jí)共享 | static 修飾的字段屬于「類本身」,而非某個(gè)實(shí)例;所有該類的實(shí)例共享同一個(gè)靜態(tài)變量 | 整棟樓的公共飲水機(jī)(靜態(tài)變量),所有房間(實(shí)例)都能接水 |
三、解決方案:借殼注入 + 靜態(tài)共享
1. 方案核心思路
通過@Component讓 Spring 創(chuàng)建一個(gè)「工具人實(shí)例」完成依賴注入,再將注入的 Bean 存入靜態(tài)變量(類級(jí)共享空間),最終讓所有非 Spring 實(shí)例從靜態(tài)變量中獲取依賴。
2. 分步實(shí)現(xiàn)
步驟 1:給 WebSocketServer 添加 @Component 注解(借殼)
給 WebSocketServer 類標(biāo)注@Component,讓 Spring 掃描并創(chuàng)建一個(gè)「工具人實(shí)例」(該實(shí)例僅用于觸發(fā)注入,不會(huì)被實(shí)際業(yè)務(wù)使用):
@Component // 關(guān)鍵:讓Spring掃描并創(chuàng)建工具人實(shí)例
public class WebSocketServer {
// 靜態(tài)字段:類級(jí)共享的"公共倉庫"
private static UserMapper userMapper;
// 普通成員變量:僅用于接收Spring注入的Bean
@Autowired
private UserMapper tempUserMapper;
// 注入完成后,將Bean存入靜態(tài)字段
@PostConstruct // 替代setter,初始化階段執(zhí)行更規(guī)范
public void init() {
// 核心:把Spring注入的Bean存入靜態(tài)變量
WebSocketServer.userMapper = this.tempUserMapper;
}
// WebSocket框架調(diào)用的核心方法
public void onMessage(String msg) {
// 從靜態(tài)變量獲取Bean,非Spring實(shí)例也能使用
userMapper.insertMessage(msg);
}
}步驟 2:執(zhí)行流程拆解
| 執(zhí)行階段 | 行為主體 | 具體動(dòng)作 | 結(jié)果 |
|---|---|---|---|
| Spring 啟動(dòng) | Spring 容器 | 掃描到 @Component,創(chuàng)建 WebSocketServer 工具人實(shí)例 | 生成一個(gè) Spring 管理的臨時(shí)對(duì)象 |
| 依賴注入 | Spring 容器 | 給工具人實(shí)例注入真實(shí)的 UserMapper 到 tempUserMapper | 工具人實(shí)例拿到有效 Bean |
| 初始化階段 | Spring 容器 | 調(diào)用 @PostConstruct 標(biāo)記的 init 方法 | 將 Bean 存入靜態(tài)變量(公共倉庫) |
| WebSocket 連接 | Tomcat 容器 | new WebSocketServer () 創(chuàng)建業(yè)務(wù)實(shí)例 | 業(yè)務(wù)實(shí)例從靜態(tài)變量獲取 UserMapper |
四、核心原理深度解析
1. 工具人實(shí)例的作用
Spring 創(chuàng)建的「工具人實(shí)例」本身不會(huì)參與任何業(yè)務(wù)邏輯,其唯一作用是:利用 Spring Bean 的訪問權(quán)限,拿到容器內(nèi)的真實(shí) Bean,并傳遞到靜態(tài)變量中。
2. 靜態(tài)變量的關(guān)鍵價(jià)值
靜態(tài)變量突破了「實(shí)例隔離」的限制:
- 普通成員變量:每個(gè)實(shí)例有獨(dú)立副本(比如實(shí)例 A 的 userMapper 和實(shí)例 B 的 userMapper 是兩個(gè)變量);
- 靜態(tài)變量:所有實(shí)例共享同一個(gè)副本(不管 new 多少個(gè) WebSocketServer,都訪問同一個(gè) userMapper)。
3. 方案本質(zhì)

以上就是在非Spring管理對(duì)象中注入Spring Bean的解決方案的詳細(xì)內(nèi)容,更多關(guān)于非Spring對(duì)象注入Spring Bean的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于ReentrantLock的實(shí)現(xiàn)原理解讀
這篇文章主要介紹了關(guān)于ReentrantLock的實(shí)現(xiàn)原理,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
Java實(shí)現(xiàn)在Word文檔中添加批注的示例代碼
在現(xiàn)代辦公環(huán)境中,Word文檔已成為信息傳遞和協(xié)作的重要載體,本教程將深入探討如何利用Java實(shí)現(xiàn)Word文檔批注的自動(dòng)化添加,感興趣的小伙伴可以了解下2025-10-10
jsp頁面中獲取servlet請(qǐng)求中的參數(shù)的辦法詳解
在JAVA WEB應(yīng)用中,如何獲取servlet請(qǐng)求中的參數(shù),本文講解了jsp頁面中獲取servlet請(qǐng)求中的參數(shù)的辦法2018-03-03
RocketMQ中多消息不同狀態(tài)回查的設(shè)計(jì)與優(yōu)化過程
文章介紹了事務(wù)狀態(tài)回查的觸發(fā)條件、核心挑戰(zhàn)、方案設(shè)計(jì)、實(shí)現(xiàn)、優(yōu)化策略及監(jiān)控告警,通過多狀態(tài)回查,確保系統(tǒng)在業(yè)務(wù)異常時(shí)仍能保持最終一致性,并提升性能和穩(wěn)定性2026-01-01
關(guān)于mybatis調(diào)用存儲(chǔ)過程獲取返回值問題
這篇文章主要介紹了mybatis調(diào)用存儲(chǔ)過程獲取返回值問題,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-01-01
詳解IDEA使用Maven項(xiàng)目不能加入本地Jar包的解決方法
這篇文章主要介紹了詳解IDEA使用Maven項(xiàng)目不能加入本地Jar包的解決方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
JAVA純代碼導(dǎo)出PDF文件實(shí)現(xiàn)方式
本文介紹了作者通過突發(fā)奇想發(fā)布了生成PDF的博客,最初,作者通過將Word文件轉(zhuǎn)換為PDF文件實(shí)現(xiàn)導(dǎo)出PDF功能,但效果不盡如人意,后來,作者嘗試直接生成PDF文件,并修復(fù)了生成PDF時(shí)出現(xiàn)的小瑕疵,通過導(dǎo)入依賴、下載接口和下載方法的實(shí)現(xiàn)2025-01-01
java 實(shí)現(xiàn)黃金分割數(shù)的示例詳解
這篇文章主要介紹了java 實(shí)現(xiàn)黃金分割數(shù)的示例詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-02-02

