Spring中BeanFactory?FactoryBean和ObjectFactory的三種的區(qū)別
Spring中BeanFactory FactoryBean和ObjectFactory的三種的區(qū)別
引言
關(guān)于FactoryBean 和 BeanFactory的對(duì)比文章比較多,但是對(duì)ObjectFactory的描述就比較少,今天我們對(duì)比下這三種的區(qū)別。
結(jié)論
BeanFactory就是對(duì)象工廠,Spring的底層容器,用于實(shí)例化和保存對(duì)象。
FactoryBean是一個(gè)工廠對(duì)象,用于實(shí)例化創(chuàng)建過(guò)程比較復(fù)雜的對(duì)象,對(duì)象的創(chuàng)建過(guò)程是由用戶自己控制的。
ObjectFactory是某個(gè)特定的工廠,用于在項(xiàng)目啟動(dòng)時(shí),延遲實(shí)例化對(duì)象,解決循環(huán)依賴問(wèn)題,也就是三級(jí)緩存那里會(huì)用到,以及結(jié)合Scope,靈活方便的實(shí)現(xiàn)是否需要?jiǎng)?chuàng)建對(duì)象。
BeanFactory
Spring最最核心的接口,Bean工廠,從名字上就能看出這是一個(gè)工廠。它是Spring最底層的容器,負(fù)責(zé)實(shí)例化和保存Spring中的Bean。
public interface BeanFactory { String FACTORY_BEAN_PREFIX = "&"; Object getBean(String name) throws BeansException; <T> T getBean(String name, Class<T> requiredType) throws BeansException; Object getBean(String name, Object... args) throws BeansException; <T> T getBean(Class<T> requiredType) throws BeansException; <T> T getBean(Class<T> requiredType, Object... args) throws BeansException; <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType); <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType); boolean containsBean(String name); boolean isSingleton(String name) throws NoSuchBeanDefinitionException; boolean isPrototype(String name) throws NoSuchBeanDefinitionException; ## 方法很多,不再贅述 }
FactoryBean
public interface FactoryBean<T> { //返回的對(duì)象實(shí)例 T getObject() throws Exception; //Bean的類型 Class<?> getObjectType(); //true是單例,false是非單例 在Spring5.0中此方法利用了JDK1.8的新特性變成了default方法,返回true boolean isSingleton(); }
我們觀察到FactoryBean接口有三個(gè)方法。getObject
用來(lái)返回實(shí)例化后的對(duì)象。getObjectType
用來(lái)返回對(duì)象的類型。isSingleton
用來(lái)標(biāo)識(shí)對(duì)象是否為單例的,這里默認(rèn)為true,Spring會(huì)將實(shí)例化后的對(duì)象放入BeanFactory容器中。
從方法上,能推測(cè)出,這個(gè)凡是實(shí)現(xiàn)了FactoryBean接口的類,負(fù)責(zé)返回這個(gè)java類的實(shí)例化對(duì)象。
從設(shè)計(jì)模式的角度來(lái)看這就是典型的工廠方法模式。由一個(gè)特定的工廠來(lái)生產(chǎn)特定的java類的實(shí)例化對(duì)象。
那么這種寫(xiě)法有哪些好處呢?
正常情況下,Spring中在實(shí)例化對(duì)象的時(shí)候,都是由BeanFactory從上下文中獲取BeanDefinition信息,然后通過(guò)反射,調(diào)用這個(gè)java類的構(gòu)造方法進(jìn)行實(shí)例化。而現(xiàn)在這種形式,我們相當(dāng)于將實(shí)例化的功能交給了FactoryBean去實(shí)現(xiàn)。這種方式主要使用在一些比較復(fù)雜的實(shí)例化過(guò)程中,并非簡(jiǎn)單地設(shè)置一些參數(shù)或者設(shè)置的參數(shù)過(guò)多,過(guò)程中可能需要做一些復(fù)雜的解析、判斷和邏輯處理,這個(gè)時(shí)候交由Spring去通過(guò)反射進(jìn)行實(shí)例化可能就不太靈活了,
Spring容器中有兩種Bean,一種是普通的Bean對(duì)象,一種是實(shí)現(xiàn)了FactoryBean的工廠Bean對(duì)象。如果從BeanFactory中g(shù)etBean的時(shí)候,獲取到的Bean對(duì)象是工廠Bean,會(huì)自動(dòng)的調(diào)用它的getObject方法返回真實(shí)實(shí)例化對(duì)象。
如果就是需要獲取FactoryBean對(duì)象,需要在getBean的時(shí)候加上前綴’&'。
Spring自身就對(duì)FactoryBean有70多種實(shí)現(xiàn),比較常見(jiàn)的就是Proxy,Jndi等場(chǎng)景。
AOP中使用的ProxyFactoryBean。
Dubbo中使用的ReferenceBean。
Mybatis中使用的SqlSessionFactoryBean。
FactoryBean的著重于自定義創(chuàng)建對(duì)象過(guò)程,由BeanFactory通過(guò)FactoryBean來(lái)獲取目標(biāo)對(duì)象,而如果是isSingleton返回true的話spring會(huì)利用單例緩存來(lái)緩存通過(guò)FactoryBean創(chuàng)建的對(duì)象。
ObjectFactory
public interface ObjectFactory<T> { //返回的對(duì)象實(shí)例 T getObject() throws BeansException; }
這用于延遲查找的場(chǎng)景,它就是一個(gè)普通工廠,當(dāng)?shù)玫?ObjectFactory 對(duì)象時(shí),相當(dāng)于 Bean 沒(méi)有被創(chuàng)建,只有當(dāng) getObject() 方法時(shí),才會(huì)觸發(fā) Bean 實(shí)例化等生命周期。
一方面在循環(huán)依賴的時(shí)候,用于延遲初始化,見(jiàn)org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
中調(diào)用addSingletonFactory
方法,會(huì)把ObjectFactory的Lambda表達(dá)式放入三級(jí)緩存。
另一方面,在AbstractBeanFacotry在doGetBean處的使用時(shí),將創(chuàng)建對(duì)象的步驟封裝到ObjectFactory中 交給自定義的Scope來(lái)選擇是否需要?jiǎng)?chuàng)建對(duì)象來(lái)靈活的實(shí)現(xiàn)scope。除此之外ObjectFactory就是一個(gè)普通的接口
簡(jiǎn)單來(lái)說(shuō)就是通過(guò)FactoryBean你可以控制對(duì)象如何創(chuàng)建,而ObjectFactory借助Scope接口自定義scope你可以控制對(duì)象的創(chuàng)建時(shí)機(jī)也可以用來(lái)延遲初始化來(lái)解決循環(huán)依賴問(wèn)題。
參考
BeanFactory和FactoryBean對(duì)比
補(bǔ)充介紹spring中關(guān)于FactoryBean 和 ObjectFactory的認(rèn)識(shí)和區(qū)別
FactoryBean:
這個(gè)接口使你可以提供一個(gè)復(fù)雜的邏輯來(lái)生成 Bean。它本質(zhì)是一個(gè) Bean,但這個(gè) Bean 不是用來(lái)注 入到其它地方像 Service、Dao 一樣使用的,它是用來(lái)生成其它 Bean 使用的。實(shí)現(xiàn)了這個(gè)接口后, Spring 在容器初始化時(shí),把實(shí)現(xiàn)這個(gè)接口的 Bean 取出來(lái),使用接口的 getObject()方法來(lái)生成我們 要想的 Bean。當(dāng)然,那些生成 Bean 的業(yè)務(wù)邏輯也要寫(xiě) getObject()方法中。 其返回的對(duì)象不是指定類的一個(gè)實(shí)例,其返回的是該工廠 Bean 的 getObject 方法所返回的對(duì)象。創(chuàng) 建出來(lái)的對(duì)象是否屬于單例由 isSingleton 中的返回決定。
使用場(chǎng)景:
1、通過(guò)外部對(duì)類是否是單例進(jìn)行控制,該類自己無(wú)法感知
2、在創(chuàng)建 Object 對(duì)象之前進(jìn) 行初始化的操作,在 afterPropertiesSet()中完成。(一次性的初始化,保存在成員變量中,并不是 每次 getObject 都會(huì)調(diào)用 afterPropertiesSet,afterPropertiesSet 只會(huì)被調(diào)用一次)
ObjectFactory:
它的目的也是作為一個(gè)工廠,來(lái)生成 Object(這個(gè)接口只有一個(gè)方法 getObject())。這個(gè)接口一般被 用來(lái),包裝一個(gè) factory,通過(guò)個(gè)這工廠來(lái)返回一個(gè)新實(shí)例(prototype 類型)。這個(gè)接口和 FactoryBean 有點(diǎn)像,但 FactoryBean 的實(shí)現(xiàn)是被當(dāng)做一個(gè) SPI(Service Provider Interface)實(shí)例來(lái)使用在 BeanFactory 里面;ObjectFactory 的實(shí)現(xiàn)一般被用來(lái)注入到其它 Bean 中,作為 API 來(lái)使用。就像ObjectFactoryCreatingFactoryBean 的 例 子 , 它 的 返 回 值 就 是 一 個(gè) ObjectFactory , 這 個(gè) ObjectFactory 被注入到了 Bean 中,在 Bean 通過(guò)這個(gè)接口的實(shí)例,來(lái)取得我們想要的 Bean。
總的來(lái)說(shuō),F(xiàn)actoryBean 和 ObjectFactory 都是用來(lái)取得 Bean,但使用的方法和地方不同, FactoryBean 被配置好后,Spring 調(diào)用 getObject()方法來(lái)取得 Bean,ObjectFactory 配置好后, 在 Bean 里面可以取得 ObjectFactory 實(shí)例,需要我們手動(dòng)來(lái)調(diào)用 getObject()來(lái)取得 Bean。
到此這篇關(guān)于Spring中BeanFactory FactoryBean和ObjectFactory的三種的區(qū)別的文章就介紹到這了,更多相關(guān)BeanFactory FactoryBean和ObjectFactory區(qū)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java微信公眾平臺(tái)開(kāi)發(fā)(2) 微信服務(wù)器post消息體的接收
這篇文章主要為大家詳細(xì)介紹了Java微信公眾平臺(tái)開(kāi)發(fā)第二步,微信服務(wù)器post消息體的接收,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04Java實(shí)現(xiàn)作業(yè)調(diào)度的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用Java實(shí)現(xiàn)SJF算法調(diào)度,要求測(cè)試數(shù)據(jù)可以隨即輸入或從文件中讀入,文中的示例代碼講解詳細(xì),需要的可以參考一下2023-04-04SpringBoot使用@valid進(jìn)行參數(shù)校驗(yàn)的流程步驟
SpringBoot 提供了一種方便的方式來(lái)進(jìn)行參數(shù)校驗(yàn):使用 Hibernate Validator,Spring Boot 提供了一種方便的方式來(lái)進(jìn)行參數(shù)校驗(yàn):使用 Hibernate Validator,所以本文給大家介紹了SpringBoot使用@valid進(jìn)行參數(shù)校驗(yàn)的流程步驟,需要的朋友可以參考下2023-09-09java 刪除文件夾中的所有內(nèi)容而不刪除文件夾本身的實(shí)例
下面小編就為大家?guī)?lái)一篇java 刪除文件夾中的所有內(nèi)容而不刪除文件夾本身的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12java操作mongodb之多表聯(lián)查的實(shí)現(xiàn)($lookup)
這篇文章主要介紹了java操作mongodb之多表聯(lián)查的實(shí)現(xiàn)($lookup),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03關(guān)于post請(qǐng)求內(nèi)容無(wú)法重復(fù)獲取的解決方法
這篇文章主要介紹了關(guān)于post請(qǐng)求內(nèi)容無(wú)法重復(fù)獲取的解決方法,文中通過(guò)代碼示例給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-03-03java使用compareTo實(shí)現(xiàn)一個(gè)類的對(duì)象之間比較大小操作
這篇文章主要介紹了java使用compareTo實(shí)現(xiàn)一個(gè)類的對(duì)象之間比較大小操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09