簡單了解Spring中BeanFactory與FactoryBean的區(qū)別
這篇文章主要介紹了簡單了解Spring中BeanFactory與FactoryBean的區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
在Spring中有BeanFactory和FactoryBean這2個接口,從名字來看很相似,比較容易搞混。
一、BeanFactory
BeanFactory是一個接口,它是Spring中工廠的頂層規(guī)范,是SpringIoc容器的核心接口,它定義了getBean()、containsBean()等管理Bean的通用方法。Spring的容器都是它的具體實現(xiàn)如:
- DefaultListableBeanFactory
- XmlBeanFactory
- ApplicationContext
這些實現(xiàn)類又從不同的維度分別有不同的擴展。
1.1 BenaFactory源碼
public interface BeanFactory { /** * 用來獲得實例的引用,并且區(qū)分FactoryBean區(qū)分。 * 如果使用bean的名字myJndiObject獲取FactoryBean,返回的是一個工廠,而不是工廠的實例;如果需要獲得工廠實例,需要轉(zhuǎn)義。 */ String FACTORY_BEAN_PREFIX = "&"; /** * 根據(jù)bean的名稱,獲取指定的bean實例,該實例可以是共享的,也可以是獨立的. */ Object getBean(String name) throws BeansException; /** * 根據(jù)bean的名稱,獲取指定的bean實例,該實例可以是共享的,也可以是獨立的.并且增加了一個類型的檢驗。 */ <T> T getBean(String name, Class<T> requiredType) throws BeansException; Object getBean(String name, Object... args) throws BeansException; /** * 根據(jù)給定類型返回匹配的bean實例. */ <T> T getBean(Class<T> requiredType) throws BeansException; <T> T getBean(Class<T> requiredType, Object... args) throws BeansException; /** * 檢查spring的bean容器中是否包含有該bean */ boolean containsBean(String name); /** * 判斷bean的作用域是否是singleton */ boolean isSingleton(String name) throws NoSuchBeanDefinitionException; /** * 判斷bena的作用域是否是prototype */ boolean isPrototype(String name) throws NoSuchBeanDefinitionException; /** * 檢查給定名稱的bean是否和指定類型匹配.更確卻的說是通過檢查給定的bean,返回指定類型的目標對象 */ boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException; /** * 獲取給定名稱的bean的class類型 */ Class<?> getType(String name) throws NoSuchBeanDefinitionException; /** * 獲取給定bean名稱的別名,如果根據(jù)別名檢索,將會獲得原始bean名稱。 * String[] getAliases(String name); }
1.2 使用場景
- 從Ioc容器中獲取Bean(byName or byType):context.getBean("father", Father.class)、context.getBean("father")
- 檢索Ioc容器中是否包含指定的Bean: context.containsBean("father")
- 判斷Bean是否為單例: context.isSingleton("father")
二、FactoryBean
首先它是一個Bean,但又不僅僅是一個Bean。它是一個能生產(chǎn)或修飾對象生成的工廠Bean,類似于設(shè)計模式中的工廠模式和裝飾器模式。它能在需要的時候生產(chǎn)一個對象,且不僅僅限于它自身,它能返回任何Bean的實例。
2.1 FactoryBean源碼
public interface FactoryBean<T> { /** * 從工廠中獲取bean實例 */ T getObject() throws Exception; /** * 從工廠中獲取bean實例對象的類型 */ Class<?> getObjectType(); /** * 工廠創(chuàng)建的對象是否是單例 */ boolean isSingleton(); }
從它定義的接口可以看出,F(xiàn)actoryBean表現(xiàn)的是一個工廠的職責。 即一個Bean A如果實現(xiàn)了FactoryBean接口,那么A就變成了一個工廠,根據(jù)A的名稱獲取到的實際上是工廠調(diào)用getObject()返回的對象,而不是A本身,如果要獲取工廠A自身的實例,那么需要在名稱前面加上'&'符號。
- getObject('name')返回工廠中的實例
- getObject('&name')返回工廠本身的實例
通常情況下,bean 無須自己實現(xiàn)工廠模式,Spring 容器擔任了工廠的 角色;但少數(shù)情況下,容器中的 bean 本身就是工廠,作用是產(chǎn)生其他 bean 實例。由工廠 bean 產(chǎn)生的其他 bean 實例,不再由 Spring 容器產(chǎn)生,因此與普通 bean 的配置不同,不再需要提供 class 元素。
2.2 示例
先定義一個Bean實現(xiàn)FactoryBean接口:
@Component public class MyBean implements FactoryBean { private String message; public MyBean() { this.message = "通過構(gòu)造方法初始化實例"; } public MyBean(String message) { this.message = message; } @Override public Object getObject() throws Exception { // 這里并不一定要返回MyBean自身的實例,可以是其他任何對象的實例 return new MyBean("通過FactoryBean.getObject()創(chuàng)建實例"); } @Override public Class<?> getObjectType() { return MyBean.class; } public String getMessage() { return message; } @Override public boolean isSingleton() { return false; } }
MyBean實現(xiàn)了FactoryBean接口的三個方法,getObject()是可以返回任何對象的實例的,這里測試就返回MyBean自身實例,且返回前給message字段賦值。同時在構(gòu)造方法中也為message賦值。然后測試代碼中先通過名稱獲取Bean實例,打印message的內(nèi)容,再通過&+名稱獲取實例并打印message內(nèi)容。
@RunWith(SpringRunner.class) @SpringBootTest(classes = HelloApplication.class) public class FactoryBeanTest { @Autowired private ApplicationContext context; @Test public void test() { MyBean myBean1 = (MyBean) context.getBean("myBean");//返回工廠中的實例,調(diào)用FactoryBean.getObject()創(chuàng)建實例 System.out.println("myBean1 = " + myBean1.getMessage()); MyBean myBean2 = (MyBean) context.getBean("&myBean");//返回工廠本身,通過構(gòu)造方法初始化實例 System.out.println("myBean2 = " + myBean2.getMessage()); System.out.println("myBean1.equals(myBean2) = " + myBean1.equals(myBean2)); } }
打印結(jié)果:
myBean1 = 通過FactoryBean.getObject()創(chuàng)建實例 myBean2 = 通過構(gòu)造方法初始化實例 myBean1.equals(myBean2) = false
2.3 使用場景
說了這么多,為什么要有FactoryBean這個東西呢,有什么具體的作用嗎?
FactoryBean在Spring中最為典型的一個應(yīng)用就是用來創(chuàng)建AOP的代理對象。
我們知道AOP實際上是Spring在運行時創(chuàng)建了一個代理對象,也就是說這個對象,是我們在運行時創(chuàng)建的,而不是一開始就定義好的,這很符合工廠方法模式。更形象地說,AOP代理對象通過Java的反射機制,在運行時創(chuàng)建了一個代理對象,在代理對象的目標方法中根據(jù)業(yè)務(wù)要求織入了相應(yīng)的方法。這個對象在Spring中就是——ProxyFactoryBean。
所以,F(xiàn)actoryBean為我們實例化Bean提供了一個更為靈活的方式,我們可以通過FactoryBean創(chuàng)建出更為復(fù)雜的Bean實例。
三、區(qū)別
- 他們兩個都是個工廠,但FactoryBean本質(zhì)上還是一個Bean,也歸BeanFactory管理
- BeanFactory是Spring容器的頂層接口,F(xiàn)actoryBean更類似于用戶自定義的工廠接口。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持我們。
上一篇:Java9 Stream Collectors新增功能(小結(jié))
欄 目:Java
本文標題:簡單了解Spring中BeanFactory與FactoryBean的區(qū)別
本文地址:http://mengdiqiu.com.cn/a1/Java/8879.html
您可能感興趣的文章
- 01-10Springboot中@Value的使用詳解
- 01-10springboot實現(xiàn)文件上傳步驟解析
- 01-10springboot jta atomikos實現(xiàn)分布式事物管理
- 01-10java判斷是否空最簡單的方法
- 01-10SpringBoot使用RabbitMQ延時隊列(小白必備)
- 01-10如何基于SpringBoot部署外部Tomcat過程解析
- 01-10SPRING BOOT啟動命令參數(shù)及源碼詳析
- 01-10springboot集成fastDfs過程代碼實例
- 01-10springmvc級聯(lián)屬性處理無法轉(zhuǎn)換異常問題解決
- 01-10SPRINGBOOT讀取PROPERTIES配置文件數(shù)據(jù)過程詳解


閱讀排行
本欄相關(guān)
- 01-10Java實現(xiàn)動態(tài)模擬時鐘
- 01-10Springboot中@Value的使用詳解
- 01-10JavaWeb實現(xiàn)郵件發(fā)送功能
- 01-10利用Java實現(xiàn)復(fù)制Excel工作表功能
- 01-10Java實現(xiàn)動態(tài)數(shù)字時鐘
- 01-10java基于poi導(dǎo)出excel透視表代碼實例
- 01-10java實現(xiàn)液晶數(shù)字字體顯示當前時間
- 01-10基于Java驗證jwt token代碼實例
- 01-10Java動態(tài)顯示當前日期和時間
- 01-10淺談Java中真的只有值傳遞么
隨機閱讀
- 01-10delphi制作wav文件的方法
- 01-11ajax實現(xiàn)頁面的局部加載
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 01-10C#中split用法實例總結(jié)
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 04-02jquery與jsp,用jquery
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改