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