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

Spring?Prototype?Bean的四種正確使用方式

 更新時(shí)間:2026年04月03日 08:39:02   作者:程序員越  
文章主要講解了在Spring框架中正確使用PrototypeBean的方法,列舉了四種有效方式,并詳細(xì)分析了每種方式的優(yōu)缺點(diǎn)與適用場景,特別針對(duì)同一類型存在多個(gè)PrototypeBean的情況,給出了相應(yīng)的解決方案,需要的朋友可以參考下

大家有沒有遇到過“明明配置了Prototype作用域,調(diào)用時(shí)卻始終拿到同一個(gè)實(shí)例”的情況? 今天我們就從這個(gè)常見錯(cuò)誤場景入題,一步步學(xué)會(huì)Prototype Bean的正確使用方式,搞懂每種方式的優(yōu)劣,再也不踩坑!

一、高頻踩坑:單例Bean依賴Prototype Bean

我們先看一個(gè)實(shí)際開發(fā)中最容易寫錯(cuò)的代碼,大家可以對(duì)照自己的項(xiàng)目,看看有沒有類似寫法:

// 1. 定義Prototype Bean(
@Component
@Scope("prototype") 
public class PrototypeBean {
    private String id;

    // 構(gòu)造方法,每次實(shí)例化時(shí)生成唯一ID
    public PrototypeBean() {
        this.id = UUID.randomUUID().toString().substring(0, 8);
    }

    // getter方法
    public String getId() {
        return id;
    }
}

// 2. 定義Singleton Bean依賴上面的Prototype Bean
@Service
public class SingletonService {
    // 直接用@Autowired注入Prototype Bean
    @Autowired
    private PrototypeBean prototypeBean;

    // 獲取Prototype Bean的ID
    public String getPrototypeBeanId() {
        return prototypeBean.getId();
    }
}

// 3. 測試代碼
@SpringBootTest
public class PrototypeTest {
    @Autowired
    private SingletonService singletonService;

    @Test
    public void testErrorUsage() {
        // 多次調(diào)用,返回不同的ID(新實(shí)例)
        String id1 = singletonService.getPrototypeBeanId();
        String id2 = singletonService.getPrototypeBeanId();
        String id3 = singletonService.getPrototypeBeanId();

        // 結(jié)果:三次ID完全相同,說明只創(chuàng)建了一個(gè)Prototype Bean實(shí)例
        System.out.println("第一次ID:" + id1);
        System.out.println("第二次ID:" + id2);
        System.out.println("第三次ID:" + id3);
    }
}

運(yùn)行測試后會(huì)發(fā)現(xiàn),三次獲取的ID完全一致——原因很簡單:Singleton Bean是全局單例,初始化時(shí)只會(huì)注入一次Prototype Bean,后續(xù)無論調(diào)用多少次,用的都是第一次注入的那個(gè)實(shí)例,Prototype Bean的“每次新實(shí)例”特性完全失效。

既然直接注入會(huì)踩坑,那我們該如何正確獲取Prototype Bean呢?接下來,我們就逐一講解四種正確使用方式。

二、Prototype Bean 四種正確使用方式(附代碼+優(yōu)劣)

方式一:通過ApplicationContextAware 編程式獲取

核心思路:讓服務(wù)類實(shí)現(xiàn)ApplicationContextAware接口,獲取Spring容器上下文,然后通過applicationContext.getBean()方法,每次主動(dòng)獲取Prototype Bean——因?yàn)槊看握{(diào)用getBean(),Spring都會(huì)創(chuàng)建一個(gè)新的Prototype實(shí)例。

//ApplicationContextAware類
@Service
public class PrototypeBeanServiceByApplicationAware implements ApplicationContextAware {
    // Spring容器上下文
    private ApplicationContext applicationContext;

    // 實(shí)現(xiàn)接口方法,Spring會(huì)自動(dòng)注入ApplicationContext
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public PrototypeBean getPrototypeBean() {
        // 每次調(diào)用getBean(),都會(huì)創(chuàng)建新的Prototype實(shí)例
        return applicationContext.getBean(PrototypeBean.class);
    }
}

// 3. 測試代碼
@Test
public void testApplicationContextAware() {
    @Autowired
    private PrototypeBeanServiceByApplicationAware service;

    // 多次調(diào)用,觀察ID同
    String id1 = service.getPrototypeBean().getId();
    String id2 = service.getPrototypeBean().getId();
    String id3 = service.getPrototypeBean().getId();

    System.out.println("第一次ID:" + id1);
    System.out.println("第二次ID:" + id2);
    System.out.println("第三次ID:" + id3);
}

優(yōu)點(diǎn):編程方式,靈活度高,可根據(jù)業(yè)務(wù)邏輯動(dòng)態(tài)獲取Prototype Bean,不受注入方式限制。

缺點(diǎn):代碼耦合度高,服務(wù)類直接依賴Spring的ApplicationContext,脫離Spring容器后無法獨(dú)立測試;代碼冗長,每個(gè)需要的地方都要注入 ApplicationContext,或者創(chuàng)建PrototypeBeanServiceByApplicationAware 這種代理的方式

方式二:通過@Lookup 注解獲取

核心思路:使用Spring提供的**@Lookup**注解,Spring會(huì)自動(dòng)重寫該方法,每次調(diào)用方法時(shí),都會(huì)返回一個(gè)新的Prototype Bean實(shí)例。

// 用@Lookup注解的服務(wù)類
@Service
public class PrototypeBeanServiceByLookup {
    @Lookup
    public PrototypeBean getPrototypeBean() {
        return null;
    }
}

// 3. 測試代碼
@Test
public void testLookup() {
    @Autowired
    private PrototypeBeanServiceByLookup service;

    String id1 = service.getPrototypeBean().getId();
    String id2 = service.getPrototypeBean().getId();
    String id3 = service.getPrototypeBean().getId();

    System.out.println("第一次ID:" + id1);
    System.out.println("第二次ID:" + id2);
    System.out.println("第三次ID:" + id3);
}

補(bǔ)充說明:@Lookup注解也可以用在抽象方法上,spring會(huì)自動(dòng)實(shí)現(xiàn)該方法。

優(yōu)點(diǎn):相比方式一代碼簡潔,只需要一個(gè)注解和一個(gè)方法;

缺點(diǎn):要寫個(gè)空方法,讓人感覺奇怪

方式三:通過ObjectFactory 獲取

核心思路:使用Spring提供的ObjectFactory接口,它是一個(gè)“工廠類”,專門用于獲取Bean實(shí)例,注入ObjectFactory后,每次調(diào)用getObject()方法,都會(huì)返回一個(gè)新的Prototype Bean。

// 用ObjectFactory的服務(wù)類
@Service
public class PrototypeBeanServiceByObjectFactory {
    // 注入ObjectFactory
    @Autowired
    private ObjectFactory<PrototypeBean> prototypeBeanObjectFactory;

    // 每次調(diào)用getObject(),獲取新的Prototype實(shí)例
    public PrototypeBean getPrototypeBean() {
        return prototypeBeanObjectFactory.getObject();
    }
}

// 3. 測試代碼
@Test
public void testObjectFactory() {
    @Autowired
    private PrototypeBeanServiceByObjectFactory service;

    String id1 = service.getPrototypeBean().getId();
    String id2 = service.getPrototypeBean().getId();
    String id3 = service.getPrototypeBean().getId();

    System.out.println("第一次ID:" + id1);
    System.out.println("第二次ID:" + id2);
    System.out.println("第三次ID:" + id3);
}

補(bǔ)充說明:ObjectFactory是Spring的輕量級(jí)工廠接口,僅提供getObject()一個(gè)方法,專門用于“延遲獲取Bean”,適合用于獲取Prototype Bean,既解耦,又不會(huì)增加過多開銷。

優(yōu)點(diǎn):相比于@Lookup,不需要再寫個(gè)方法,直接注入即可

方式四:通過ObjectProvider 獲?。ㄍ扑])

ObjectProvider是Spring 4.3+新增的接口,是ObjectFactory的增強(qiáng)版,不僅能獲取Bean實(shí)例,還提供了多種靈活的獲取方法(比如判斷Bean是否存在、獲取唯一Bean等),是目前獲取Prototype Bean的推薦方式。

// 用ObjectProvider的服務(wù)類
@Service
public class PrototypeBeanServiceByObjectProvider {
    // 注入ObjectProvider
    @Autowired
    private ObjectProvider<PrototypeBean> prototypeBeanObjectProvider;

    // 獲取Prototype實(shí)例(和ObjectFactory類似)
    public PrototypeBean getPrototypeBean() {
        return prototypeBeanObjectProvider.getIfAvailable();
    }
}

// 3. 測試代碼
@Test
public void testObjectProvider() {
    @Autowired
    private PrototypeBeanServiceByObjectProvider service;

    String id1 = service.getPrototypeBean().getId();
    String id2 = service.getPrototypeBean().getId();
    String id3 = service.getPrototypeBean().getId();

    System.out.println("第一次ID:" + id1);
    System.out.println("第二次ID:" + id2);
    System.out.println("第三次ID:" + id3);
}

補(bǔ)充說明:getIfUnique()是獲取bean的另一種方式,簡單說下和getIfAvailable區(qū)別:

  • getIfAvailable():“有就拿,沒有就算了”(返回null),如果同類型bean有多個(gè),則拋異常;
  • getIfUnique():“有且只有一個(gè)”,否則返回null,如果同類型bean有多個(gè)也返回null。

優(yōu)點(diǎn):功能強(qiáng)大,支持多種獲取方式,是Spring推薦的方式。

四種方式我們都講完了,每種方式都有自己的優(yōu)劣和適用場景。但實(shí)際開發(fā)中,我們常會(huì)遇到同一類型存在多個(gè)Prototype Bean的情況(比如通過@Bean定義多個(gè)同類型實(shí)例),這種場景下該如何精準(zhǔn)獲取目標(biāo)Bean呢?接下來我們說下這種特殊場景的處理方法。

三、特殊場景:同一類型存在多個(gè)Prototype Bean的處理

場景代碼如下:

@Configuration
public class Config {

    // 第一個(gè)Prototype Bean,bean名稱默認(rèn)是方法名prototypeBean
    @Bean
    @Scope("prototype")
    public PrototypeBean prototypeBean() {
        return new PrototypeBean();
    }

    // 第二個(gè)Prototype Bean,bean名稱為prototypeBeanA
    @Bean
    @Scope("prototype")
    public PrototypeBean prototypeBeanA() {
        return new PrototypeBean();
    }

    // 第三個(gè)Prototype Bean,bean名稱為prototypeBeanB
    @Bean
    @Scope("prototype")
    public PrototypeBean prototypeBeanB() {
        return new PrototypeBean();
    }
}

此時(shí)容器中存在3個(gè)PrototypeBean類型的Bean。此時(shí)直接用之前的方式獲取會(huì)出現(xiàn)問題,可能返回null,可能報(bào)錯(cuò),我們針對(duì)四種方式,分別給出解決方案:

1. 方式一(ApplicationContextAware):通過getBean指定bean名稱

核心思路:在調(diào)用applicationContext.getBean()方法時(shí),增加一個(gè)參數(shù)(bean名稱),精準(zhǔn)指定要獲取的目標(biāo)Bean,避免歧義。

@Service
public class PrototypeBeanServiceByApplicationAware implements ApplicationContextAware {
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    // 分別獲取不同名稱的Prototype Bean
    public PrototypeBean getPrototypeBean() {
        // 指定bean名稱為prototypeBean
        return applicationContext.getBean("prototypeBean", PrototypeBean.class);
    }

}

2. 方式二(@Lookup注解):通過@Lookup指定bean名稱

核心思路:在@Lookup注解中添加value屬性,指定目標(biāo)Bean的名稱。

@Service
public class PrototypeBeanServiceByLookup {
    // 指定獲取名稱為prototypeBean的Bean
    @Lookup("prototypeBean")
    public PrototypeBean getPrototypeBean() {
        return null;
    }
}

3. 方式三、方式四(ObjectFactory/ObjectProvider):通過字段名匹配bean名稱

核心思路:Spring自動(dòng)注入時(shí),會(huì)根據(jù)字段名匹配容器中的Bean名稱,即可精準(zhǔn)獲取對(duì)應(yīng)實(shí)例。

@Service
public class PrototypeBeanServiceByObjectFactory {
    // 字段名=bean名稱,獲取該名稱的Bean
    @Autowired
    private ObjectFactory<PrototypeBean> prototypeBean;

    // 獲取方法
    public PrototypeBean getPrototypeBean() {
        return prototypeBean.getObject();
    }

}

總結(jié):同一類型存在多個(gè)Prototype Bean時(shí),核心是“通過名稱定位Bean”。

四、總結(jié):四種方式對(duì)比與選擇

使用方式核心優(yōu)點(diǎn)核心缺點(diǎn)
ApplicationContextAware靈活度高,可動(dòng)態(tài)獲取耦合Spring容器,測試不便
@Lookup注解代碼簡潔需要添加一個(gè)“雞肋”方法
ObjectFactory直接注入,簡便多bean時(shí),如果不處理會(huì)拋異常
ObjectProvider功能強(qiáng)大,靈活,Spring推薦

總結(jié):日常開發(fā)中,優(yōu)先選擇ObjectProvider;如果場景簡單,可選擇@Lookup或ObjectFactory;只有需要?jiǎng)討B(tài)Bean獲取邏輯時(shí),才考慮ApplicationContextAware。

以上就是Spring Prototype Bean的四種正確使用方式的詳細(xì)內(nèi)容,更多關(guān)于Spring Prototype Bean使用方式的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java yaml轉(zhuǎn)properties工具類方式

    java yaml轉(zhuǎn)properties工具類方式

    這篇文章主要介紹了java yaml轉(zhuǎn)properties工具類方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • springboot結(jié)合ehcache防止惡意刷新請求的實(shí)現(xiàn)

    springboot結(jié)合ehcache防止惡意刷新請求的實(shí)現(xiàn)

    這篇文章主要介紹了springboot結(jié)合ehcache防止惡意刷新請求的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • 利用ScriptEngineManager實(shí)現(xiàn)字符串公式靈活計(jì)算的方法

    利用ScriptEngineManager實(shí)現(xiàn)字符串公式靈活計(jì)算的方法

    今天小編就為大家分享一篇利用ScriptEngineManager實(shí)現(xiàn)字符串公式靈活計(jì)算的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-07-07
  • 基于Java實(shí)現(xiàn)本地APK文件搜索與HTTP下載服務(wù)

    基于Java實(shí)現(xiàn)本地APK文件搜索與HTTP下載服務(wù)

    在移動(dòng)應(yīng)用開發(fā)和測試過程中,經(jīng)常需要從本地服務(wù)器獲取最新的 APK 安裝包,本文將詳細(xì)介紹如何使用 Java 構(gòu)建一個(gè)能夠搜索本地最新 APK 文件并通過 HTTP 請求提供下載服務(wù)的應(yīng)用
    2025-07-07
  • SpringCloud搭建Eureka服務(wù)模塊的過程

    SpringCloud搭建Eureka服務(wù)模塊的過程

    Eureka在分布式系統(tǒng)中起到了連接各個(gè)微服務(wù)的紐帶作用,使得服務(wù)之間的交互變得更加靈活、可靠,本文將深入探討如何使用Spring?Cloud,逐步引導(dǎo)讀者完成Eureka服務(wù)模塊的搭建,感興趣的朋友跟隨小編一起看看吧
    2024-02-02
  • Java字符串拼接詳解

    Java字符串拼接詳解

    大家好,本篇文章主要講的是Java字符串拼接詳解,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下
    2022-02-02
  • spring boot springjpa 支持多個(gè)數(shù)據(jù)源的實(shí)例代碼

    spring boot springjpa 支持多個(gè)數(shù)據(jù)源的實(shí)例代碼

    這篇文章主要介紹了spring boot springjpa 支持多個(gè)數(shù)據(jù)源的實(shí)例代碼,需要的朋友可以參考下
    2018-04-04
  • Java AbstractMethodError案例分析詳解

    Java AbstractMethodError案例分析詳解

    這篇文章主要介紹了Java AbstractMethodError案例分析詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • 詳談@Autowired和static的關(guān)系

    詳談@Autowired和static的關(guān)系

    這篇文章主要介紹了@Autowired和static的關(guān)系,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Mybatis調(diào)用MySQL存儲(chǔ)過程的簡單實(shí)現(xiàn)

    Mybatis調(diào)用MySQL存儲(chǔ)過程的簡單實(shí)現(xiàn)

    本篇文章主要介紹了Mybatis調(diào)用MySQL存儲(chǔ)過程的簡單實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-04-04

最新評(píng)論

怀集县| 化隆| 霍山县| 石城县| 郯城县| 贵定县| 汉川市| 黔江区| 樟树市| 孟村| 潢川县| 罗山县| 石家庄市| 北碚区| 永福县| 武平县| 凯里市| 梅河口市| 清丰县| 高淳县| 澄迈县| 临颍县| 常宁市| 洪湖市| 桃源县| 霍城县| 措勤县| 云阳县| 塔河县| 达州市| 万山特区| 井陉县| 林芝县| 禹城市| 滦南县| 剑河县| 寻乌县| 江城| 佛坪县| 叙永县| 高邑县|