高端網(wǎng)站開(kāi)發(fā)建設(shè)網(wǎng)絡(luò)營(yíng)銷知識(shí)點(diǎn)
目錄
優(yōu)勢(shì)
解決依賴注入失效問(wèn)題:
典型應(yīng)用場(chǎng)景:
好處
1. 實(shí)例化時(shí)序問(wèn)題
2. 延遲獲取解決空指針
3. 設(shè)計(jì)模式與 Spring 的權(quán)衡
代碼對(duì)比:錯(cuò)誤 vs 正確
錯(cuò)誤示例(空指針):
正確實(shí)現(xiàn)(延遲獲取):
總結(jié)
優(yōu)勢(shì)
在單例模式中通過(guò)SpringUtil.getBean獲取Bean有以下幾個(gè)關(guān)鍵優(yōu)勢(shì):
解決依賴注入失效問(wèn)題:
-
- AsyncManager是餓漢式單例,實(shí)例化時(shí)機(jī)早于Spring容器初始化
- 使用@Autowired等注入方式會(huì)導(dǎo)致NullPointerException
- getBean()延遲獲取保證了Spring容器完成初始化后才獲取Bean
1. 保持單例控制權(quán):
- 該類自己維護(hù)單例實(shí)例(非Spring管理)
- 避免與Spring容器管理的單例產(chǎn)生沖突
- 可以自主控制初始化和銷毀時(shí)機(jī)
2. 獲取復(fù)雜依賴的靈活性:
- 當(dāng)需要?jiǎng)討B(tài)獲取不同profile配置的Bean時(shí)更靈活
- 特別適用于需要根據(jù)條件獲取不同實(shí)現(xiàn)類的場(chǎng)景
3. 避免循環(huán)依賴陷阱:
- 傳統(tǒng)注入方式在復(fù)雜依賴鏈中可能引發(fā)循環(huán)依賴問(wèn)題
- 按需主動(dòng)獲取的方式打破了這種潛在的循環(huán)依賴鏈
4. 與工具類整合更自然:
- 結(jié)合Hutool等工具庫(kù)的使用風(fēng)格
- 保持代碼簡(jiǎn)潔性,避免大量注解污染
典型應(yīng)用場(chǎng)景:
- 框架基礎(chǔ)組件
- 需要嚴(yán)格生命周期控制的類
- 早于Spring容器初始化的核心組件
- 需要避免被Spring代理的場(chǎng)合
這種模式在中間件開(kāi)發(fā)、基礎(chǔ)框架開(kāi)發(fā)中較為常見(jiàn),體現(xiàn)了對(duì)Spring容器的主動(dòng)控制,而非被動(dòng)依賴。
好處
1. 實(shí)例化時(shí)序問(wèn)題
- 根本矛盾:
AsyncManager
是餓漢式單例,其靜態(tài)實(shí)例INSTANCE
在類加載時(shí)(通常是應(yīng)用啟動(dòng)早期)立即初始化。而此時(shí) Spring 容器可能尚未完成 Bean 的初始化。 - 傳統(tǒng)注入的陷阱:如果用
@Autowired
注入ScheduledExecutorService
:
@Autowired
private ScheduledExecutorService executor; // 此時(shí)Spring容器未就緒,注入會(huì)失敗!
由于單例的初始化早于 Spring 容器的初始化,executor
會(huì)保持 null
,后續(xù)使用時(shí)必然拋出 NullPointerException
。
2. 延遲獲取解決空指針
- 按需獲取:通過(guò)
SpringUtil.getBean("scheduledExecutorService")
延遲加載 Bean:
-
- 第一次調(diào)用
execute()
方法時(shí)才會(huì)實(shí)際獲取 Bean - 此時(shí) Spring 容器已經(jīng)初始化完成,可以安全獲取到 Bean
- 第一次調(diào)用
- 避免靜態(tài)代碼塊陷阱:即使你在靜態(tài)代碼塊中調(diào)用
SpringUtil.getBean()
,仍然可能因容器未就緒而失敗,而延遲加載徹底規(guī)避了時(shí)序問(wèn)題。
3. 設(shè)計(jì)模式與 Spring 的權(quán)衡
- 單例控制權(quán):
AsyncManager
是一個(gè)自主管理的單例(非 Spring 托管),因此:
-
- 它不參與 Spring 的生命周期管理
- 不能直接享受 Spring 的依賴注入特性
- 需要主動(dòng)從容器中獲取依賴,而非被動(dòng)注入
- 框架整合技巧:通過(guò)
SpringUtil
工具類(Hutool 提供)打破單例模式與 Spring 容器的耦合,是常見(jiàn)的企業(yè)級(jí)解決方案。
代碼對(duì)比:錯(cuò)誤 vs 正確
錯(cuò)誤示例(空指針):
public class AsyncManager {private static final AsyncManager INSTANCE = new AsyncManager();@Autowired // 注入時(shí)機(jī)不對(duì)!private ScheduledExecutorService executor;public void execute(TimerTask task) {executor.schedule(task, 10, TimeUnit.MILLISECONDS); // executor 為 null!}
}
正確實(shí)現(xiàn)(延遲獲取):
public class AsyncManager {private static final AsyncManager INSTANCE = new AsyncManager();// 延遲獲取 Beanprivate final ScheduledExecutorService executor = SpringUtil.getBean("scheduledExecutorService"); public void execute(TimerTask task) {executor.schedule(task, 10, TimeUnit.MILLISECONDS); // 安全執(zhí)行}
}
總結(jié)
- 核心目標(biāo):確保在 Spring 容器初始化完成后再獲取 Bean,避免
NullPointerException
- 設(shè)計(jì)權(quán)衡:犧牲一定的 "純粹性"(依賴注入的理想模式),換取代碼的健壯性和框架整合的靈活性
- 適用場(chǎng)景:自主管理的單例類、工具類、需要早期初始化的組件等
這種模式在需要嚴(yán)格掌控初始化時(shí)序的場(chǎng)景中非常實(shí)用,是解決框架整合時(shí)序問(wèn)題的經(jīng)典方案。