最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring單例類加載多例屬性問題實例解析

 更新時間:2026年03月06日 11:14:15   作者:Hui  Baby  
本文給大家介紹Spring單例類加載多例屬性問題實例解析,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧

Spring 的 多例(Prototype)作用域 (scope="prototype") 實現(xiàn)“每次請求都生成新對象”的核心機制,其實非常簡單直接:

它完全不緩存 Bean 實例。

與單例(Singleton)不同,Spring 容器內(nèi)部沒有一個 Map 來存儲 Prototype Bean 的實例。每次你調(diào)用 getBean() 或注入該 Bean 時,Spring 都會重新執(zhí)行完整的創(chuàng)建流程。

1. 核心流程對比

為了讓你看清區(qū)別,我們對比一下 Singleton 和 Prototype 的處理邏輯:

?? 單例 (Singleton) - “查緩存,沒有才造”

// 偽代碼:Spring 內(nèi)部邏輯
public Object getBean(String beanName) {
    // 1. 先查一級緩存 (singletonObjects)
    Object bean = singletonObjects.get(beanName);
    // 2. 如果有,直接返回 (秒回,不創(chuàng)建)
    if (bean != null) {
        return bean;
    }
    // 3. 如果沒有,才創(chuàng)建,并放入緩存
    bean = createBean(beanName);
    singletonObjects.put(beanName, bean); // <--- 關(guān)鍵:存起來
    return bean;
}

結(jié)果:第一次創(chuàng)建,后續(xù)無數(shù)次都是返回同一個對象。

?? 多例 (Prototype) - “不管有沒有,每次都造”

// 偽代碼:Spring 內(nèi)部邏輯 (AbstractBeanFactory.doGetBean)
public Object getBean(String beanName) {
    // 1. 獲取 Bean 定義
    RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
    // 2. 判斷作用域
    if (mbd.isPrototype()) {
        // 【關(guān)鍵點】:直接進(jìn)入創(chuàng)建流程,完全不查緩存!
        // 也不會在創(chuàng)建后存入任何緩存
        return createBean(beanName, mbd, args); 
    }
    // ... 單例的其他邏輯 ...
}

結(jié)果:每次調(diào)用 createBean,都是一次全新的生命周期(實例化 -> 屬性填充 -> 初始化)。

2. 詳細(xì)執(zhí)行步驟

當(dāng)你請求一個 Prototype Bean 時,Spring 內(nèi)部會發(fā)生以下過程:

  1. 解析定義:讀取 XML 或注解中的 @Scope("prototype") 配置。
  2. 跳過緩存檢查:代碼邏輯直接判定為多例,跳過 getSingleton() 這種緩存查找操作。
  3. 調(diào)用 createBean()
    • 實例化 (Instantiation):調(diào)用構(gòu)造函數(shù)(或工廠方法)new YourClass()。
    • 屬性填充 (Populate):依賴注入 (@Autowired@Value)。
    • 初始化 (Initialization):執(zhí)行 @PostConstructInitializingBean.afterPropertiesSet(), 自定義 init-method。
  4. 返回對象:將創(chuàng)建好的全新對象返回給調(diào)用者。
  5. 放手不管Spring 容器不再持有該對象的引用
    • 這意味著:Spring 不會管理 Prototype Bean 的完整生命周期。
    • 特別是:Spring 不會自動調(diào)用 @PreDestroy 或 destroy-method。因為容器不知道這個對象去哪了,也不知道什么時候該銷毀它(由調(diào)用者負(fù)責(zé)垃圾回收)。

3. 源碼級證據(jù)

在 Spring 的核心類 AbstractBeanFactory 的 doGetBean 方法中,有非常明確的邏輯分支:

// org.springframework.beans.factory.support.AbstractBeanFactory.java
protected <T> T doGetBean(...) {
    // ... 前置處理 ...
    // 判斷作用域
    String scopeName = mbd.getScope();
    if (scopeName != null) {
        if (scopeName.equals(ConfigurableBeanFactory.SCOPE_PROTOTYPE)) {
            // 【核心代碼】
            // 如果是 prototype,直接調(diào)用 createBean,沒有任何緩存邏輯
            Object bean = createBean(beanName, mbd, args);
            return (T) bean;
        }
        // 如果是 request/session 等其它作用域,會使用 Scope 接口處理
        else if (scopeName.equals(ConfigurableBeanFactory.SCOPE_REQUEST)) {
             // ...
        }
    }
    // 如果是 singleton (默認(rèn)),走下面的緩存邏輯
    // ... sharedInstance = getSingleton(...) ...
}

可以看到,對于 SCOPE_PROTOTYPE,代碼路徑是最短、最直接的,直接調(diào)用了創(chuàng)建方法。

4. 常見誤區(qū)與坑

? 誤區(qū) 1:以為注入到單例 Bean 中也能每次變新

這是最常見的錯誤!

@Component // 默認(rèn)是 Singleton
public class UserService {
    @Autowired
    private ActionService actionService; // 假設(shè) ActionService 是 Prototype
}
  • 現(xiàn)象UserService 是單例,它在 Spring 啟動時只會被創(chuàng)建一次。
  • 結(jié)果:在創(chuàng)建 UserService 的那一瞬間,Spring 注入了一個 ActionService 實例。此后,無論你怎么用 UserService,里面的 actionService 永遠(yuǎn)是同一個對象,不會變!
  • 原因:依賴注入發(fā)生在 Bean 創(chuàng)建時。單例 Bean 只創(chuàng)建一次,所以依賴也只注入一次。

? 解決方案:如何在一個單例中獲取多例?

如果你需要在單例中每次都用新的 Prototype 對象,有三種方法:

方法注入 (Lookup Method Injection) - 推薦,純注解
使用 @Lookup 注解,Spring 會在運行時動態(tài)重寫這個方法,每次調(diào)用都去容器 getBean

@Component
public class UserService {
    @Lookup
    protected ActionService createActionService() {
        // 方法體可以是空的,Spring 會覆蓋它
        return null; 
    }
    public void doWork() {
        ActionService action = createActionService(); // 每次都是新的
    }
}

注入 ObjectFactory 或 Provider - 推薦,標(biāo)準(zhǔn)寫法
注入一個工廠對象,需要時手動 getObject()

@Component
public class UserService {
    @Autowired
    private ObjectProvider<ActionService> actionProvider;
    public void doWork() {
        ActionService action = actionProvider.getObject(); // 每次都是新的
    }
}

直接從 ApplicationContext 獲取 - 不推薦,耦合度

@Autowired
private ApplicationContext context;
public void doWork() {
    ActionService action = context.getBean(ActionService.class);
}

     4.是要@Lazy注解標(biāo)記多例對象

       @lazy啟動時候創(chuàng)建代理類,在調(diào)用時候執(zhí)行獲取對象,生成代理對象,走getBean,由于標(biāo)注多例,則會重寫createBean創(chuàng)建新的對象

特性@Lazy 注入ObjectProvider 注入@Lookup 注解
能否獲取新實例 (Spring 5+)
代碼可讀性??? (意圖是“延遲”,多例是隱含的)????? (意圖明確:“我要工廠”)???? (意圖明確,但需抽象方法)
靈活性?? (只能直接調(diào)用方法)????? (可判斷 ifAvailable, 流式操作 stream())?? (只能獲取)
底層原理AOP 代理 (JDK 或 CGLIB)依賴注入工廠對象CGLIB 方法重寫
推薦指數(shù)推薦 (簡單場景夠用)強烈推薦 (最佳實踐)推薦 (無參構(gòu)造場景)

5. 總結(jié)

Spring 多例對象之所以能每次生成新的,是因為:

  1. 策略不同:它在 doGetBean 階段就跳過了所有緩存檢查
  2. 動作直接:直接調(diào)用 createBean() 執(zhí)行完整的實例化和初始化流程。
  3. 無狀態(tài)管理:創(chuàng)建完成后,容器立即斷開引用,不保存、不跟蹤、不銷毀。

這就好比自動售貨機(單例)和現(xiàn)做冰淇淋攤(多例):

  • 自動售貨機:貨都在柜子里(緩存),有人買直接拿,賣完了才補貨。
  • 冰淇淋攤:每次有人買,老板都重新挖球、裝筒(createBean),做完給你,手里不留貨(不緩存)。

到此這篇關(guān)于spring單例類加載多例屬性問題的文章就介紹到這了,更多相關(guān)spring單例類加載多例屬性內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JavaWeb中導(dǎo)出excel文件的簡單方法

    JavaWeb中導(dǎo)出excel文件的簡單方法

    下面小編就為大家?guī)硪黄狫avaWeb中導(dǎo)出excel文件的簡單方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-10-10
  • Mybatis-Plus開發(fā)提速器generator的使用

    Mybatis-Plus開發(fā)提速器generator的使用

    本文就介紹這款基于Mybatis-Plus的代碼自助生成器,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • 基于idea 的 Java中的get/set方法之優(yōu)雅的寫法

    基于idea 的 Java中的get/set方法之優(yōu)雅的寫法

    這篇文章主要介紹了基于idea 的 Java中的get/set方法之優(yōu)雅的寫法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-01-01
  • 基于Java代碼實現(xiàn)數(shù)字在數(shù)組中出現(xiàn)次數(shù)超過一半

    基于Java代碼實現(xiàn)數(shù)字在數(shù)組中出現(xiàn)次數(shù)超過一半

    這篇文章主要介紹了基于Java代碼實現(xiàn)數(shù)字在數(shù)組中出現(xiàn)次數(shù)超過一半的相關(guān)資料,需要的朋友可以參考下
    2016-02-02
  • SpringMVC?@RequestMapping注解詳解

    SpringMVC?@RequestMapping注解詳解

    本文主要介紹了SpringMVC?@RequestMapping注解詳解,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • Maven直接依賴、間接依賴、依賴沖突、依賴仲裁的實現(xiàn)

    Maven直接依賴、間接依賴、依賴沖突、依賴仲裁的實現(xiàn)

    本文主要介紹了Maven直接依賴、間接依賴、依賴沖突、依賴仲裁的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-09-09
  • IntelliJ IDEA中代碼一鍵生成方法

    IntelliJ IDEA中代碼一鍵生成方法

    EasyCode 是基于 IntelliJ IDEA 開發(fā)的代碼生成插件,支持自定義任意模板(Java,html,js,xml),這篇文章主要介紹了IntelliJ IDEA中代碼一鍵生成方法,需要的朋友可以參考下
    2020-02-02
  • SpringBoot 多環(huán)境配置和啟動詳解

    SpringBoot 多環(huán)境配置和啟動詳解

    這篇文章主要為大家介紹了SpringBoot多環(huán)境配置和啟動詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • JAVA?流程控制專項精講

    JAVA?流程控制專項精講

    不喜歡羅里吧嗦,講的很精簡易懂。從基礎(chǔ)開始講,后續(xù)會講到JAVA高級,中間會穿插面試題和項目實戰(zhàn),希望能給大家?guī)韼椭?/div> 2022-03-03
  • Eclipse 出現(xiàn)Failed to load JavaHL Library解決方法

    Eclipse 出現(xiàn)Failed to load JavaHL Library解決方法

    這篇文章主要介紹了Eclipse 出現(xiàn)Failed to load JavaHL Library解決方法的相關(guān)資料,今天使用Eclipse 時出現(xiàn)以上錯誤,本文說明如何更更正,需要的朋友可以參考下
    2016-11-11

最新評論

巴彦淖尔市| 安岳县| 光泽县| 昌江| 洛川县| 勐海县| 随州市| 东海县| 通许县| 札达县| 紫金县| 安顺市| 唐山市| 西丰县| 盐池县| 扬州市| 大兴区| 嘉鱼县| 黔东| 郴州市| 梁平县| 邵阳县| 忻城县| 和平县| 信丰县| 吴堡县| 河南省| 莎车县| 内乡县| 名山县| 博乐市| 烟台市| 电白县| 大新县| 布拖县| 泾阳县| 景东| 忻州市| 双城市| 绵竹市| 科技|