首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Spring Bean 作用域選擇指南:何時用 Singleton、何時用 Prototype

     編輯:程式設計綜合問答

核心判斷標準

當對象包含可變狀態 (且該狀態在實際業務中會被修改) 時 → Prototype (多例)
否則 → Singleton (單例)

四個核心問題解析

1. 什麼是單例/多例?

  • Singleton:Spring 容器中**僅存在一個實例**,所有注入點、所有請求**共享同一對象**。默認作用域。
  • Prototype:每次 `getBean()`、每次注入、每次請求 (配合 `ScopedProxy`)**創建新實例**,互不干擾。

2. 如何配置?



 



@Service // 默認 singleton
@Scope("prototype") // 或 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class MyAction { ... }

3. 為什麼這樣選?

選擇理由
Singleton避免重複創建開銷 (CPU/內存/GC);無狀態對象天然線程安全;依賴注入圖簡單高效
Prototype隔離可變狀態,防止併發請求數據污染;每個請求/任務擁有獨立上下文

4. 具體場景對照表

層/組件推薦 Scope理由反例後果
Controller (Spring MVC)Singleton參數通過方法傳遞,無實例字段狀態加字段存請求參數 → 併發錯亂
ServiceSingleton業務邏輯無狀態,只協調 Dao在 Service 中存用戶信息 → 數據洩露
Dao / RepositorySingleton數據訪問無狀態,線程安全極少見,除非 Dao 持有連接/事務狀態
Struts2 ActionPrototype框架設計:Action 實例字段綁定請求參數Singleton → 參數覆蓋、驗證錯誤共享
Struts1 ActionSingleton參數在 ActionForm 中,Action 無狀態—
有狀態工具類Prototype如報表生成器、線程上下文持有者Singleton → 數據混亂
請求/會話作用域request / sessionWeb 環境專用,生命周期綁定 HTTP—

隱藏陷阱:Service 中意外引入狀態


@Service
public class OrderService {
    // 危險!實例字段存儲請求相關數據
    private String currentUserId; 
    private List cachedOrders; 
    
    public void setUser(String userId) { this.currentUserId = userId; }
    public List getOrders() { return cachedOrders; }
}

**後果**:併發請求 A 設置 userId=1,請求 B 設置 userId=2 → A 獲取訂單時可能拿到 B 的數據。**極難復現、極難定位**。

**修正**:參數傳遞、ThreadLocal (謹慎)、RequestScope Bean。

如何發現錯誤的 Scope?

  1. 代碼審查**:檢查非 Controller/Action 類中是否有非 final 實例字段被修改。
  2. 壓力測試**:併發請求同一接口,驗證數據隔離性。
  3. 啟用 Spring 檢測**:`spring.main.allow-bean-definition-overriding=false` 等嚴格模式。

總結口訣

無狀態 → Singleton (默認、高效)
有狀態 → Prototype (隔離、安全)
Web 請求 → request/session (框架原生)
Service/Dao → 默認 Singleton,堅決不加字段存請求數據

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved