Spring中的FactoryBean實(shí)現(xiàn)原理詳解
1、概述
spring中有兩種類型的Bean:
- 一種是普通的JavaBean;
- 另一種就是工廠Bean(FactoryBean)
這兩種Bean都受Spring的IoC容器管理,但它們之間卻有一些區(qū)別。
2、詳述
普通的JavaBean不再多說,我們將其定義好,然后在配置文件中定義并配置其依賴關(guān)系,就可以通過IoC容器的getBean獲取到。
那么FactoryBean呢?
FactoryBean跟普通Bean不同,它是實(shí)現(xiàn)了FactoryBean<T>接口的Bean,通過BeanFactory類的getBean方法直接獲取到的并不是該FactoryBean的實(shí)例,而是該FactoryBean中方法getObject返回的對象。但我們可以通過其它途徑獲取到該FactoryBean的實(shí)例,方法就是在通過getBean方法獲取實(shí)例時在參數(shù)name前面加上“&”符號即可。
FactoryBean接口提供的方法如下:
public interface FactoryBean<T> { //獲取FactoryBean初始化的Bean實(shí)例 T getObject() throws Exception; //獲取Bean實(shí)例的類型 Class<?> getObjectType(); //判斷是否是單例模式 boolean isSingleton(); }
3、示例
創(chuàng)建MyFactoryBean
public class MyFactoryBean implements FactoryBean<Date>,BeanNameAware { private String name; @Override public Date getObject() throws Exception { return new Date(); } @Override public Class<?> getObjectType() { return Date.class; } @Override public boolean isSingleton() { return false; } public void sayName() { System.out.println("My name is " + this.name); } @Override public void setBeanName(String name) { this.name = name; } }
在Spring的配置文件ApplicationContext.xml中注入MyFactoryBean
<bean id ="myFactoryBean" class="com.xxxx.MyFactoryBean"></bean>
測試代碼
public class MainFactoryBean { @SuppressWarnings("resource") public static void main(String [] args){ ApplicationContext appCtx = new ClassPathXmlApplicationContext("applicationContext.xml"); Date now = (Date) appCtx.getBean("myFactoryBean"); System.out.println(now); MyFactoryBean factoryBean = (MyFactoryBean) appCtx.getBean("&myFactoryBean"); factoryBean.sayName(); } }
運(yùn)行結(jié)果
通過myFactoryBean名稱獲取到的Bean是Date對象實(shí)例,通過&myFactoryBean獲取到的是MyFactoryBean對象實(shí)例。
4、實(shí)現(xiàn)原理
我們來看一下執(zhí)行Date now = (Date) appCtx.getBean("myFactoryBean"); 時會做的處理操作。 AbstractBeanFactory中會進(jìn)行一系列的操作。
getBean獲取bean
@Override public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); }
doGetBean中獲取bean實(shí)例
protected <T> T doGetBean( final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { .........//省略部分代碼 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); .........//省略部分代碼 return (T) bean; }
getObjectForBeanInstance中會選擇bean實(shí)例是普通的Bean還是FactoryBean,同時通過判斷name中是否有&來選擇判斷是或者FactoryBean還是其getObject方法中獲取的bean
protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, RootBeanDefinition mbd) { .........//省略部分代碼 //判斷bean類型是否是FactoryBean,或者name是否是以&開頭,如果是則直接返回 if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { return beanInstance; } //如果是則從getObjectFromFactoryBean中獲取 if (object == null) { // Return bean instance from factory. FactoryBean<?> factory = (FactoryBean<?>) beanInstance; if (mbd == null && containsBeanDefinition(beanName)) { mbd = getMergedLocalBeanDefinition(beanName); } boolean synthetic = (mbd != null && mbd.isSynthetic()); object = getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; }
getObjectFromFactoryBean接下來會執(zhí)行FactoryBean的getObject方法獲取bean了。
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) { .........//省略部分代碼 Object object = doGetObjectFromFactoryBean(factory, beanName); .........//省略部分代碼 return object; } private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName) throws BeanCreationException { Object object; .........//省略部分代碼 //調(diào)用Factory的getObject方法 object = factory.getObject(); .........//省略部分代碼 return object; }
總結(jié)
Spring對FactoryBean的實(shí)現(xiàn)機(jī)制是當(dāng)你獲取一個Bean時,如果獲取的Bean的類型是FactoryBean,并且其name中并沒有&則調(diào)用bean的getObject方法獲取FactoryBean實(shí)現(xiàn)類中提供bean,否則就是直接返回普通的bean類型。
到此這篇關(guān)于Spring中的FactoryBean實(shí)現(xiàn)原理詳解的文章就介紹到這了,更多相關(guān)FactoryBean實(shí)現(xiàn)原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring中的BeanFactory與FactoryBean區(qū)別詳解
- SpringBoot升級3.2報錯Invalid value type for attribute ‘factoryBeanObjectType‘: java.lang.String的解決方案
- Spring中的FactoryBean與ObjectFactory詳解
- Spring中BeanFactory與FactoryBean的區(qū)別解讀
- Spring中的FactoryBean與BeanFactory詳細(xì)解析
- Spring的FactoryBean<Object>接口示例代碼
- 簡單了解Spring中BeanFactory與FactoryBean的區(qū)別
相關(guān)文章
Java fastjson解析json字符串實(shí)現(xiàn)過程解析
這篇文章主要介紹了Java fastjson解析json字符串實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-10-10springboot項(xiàng)目docker分層構(gòu)建的配置方式
在使用dockerfile構(gòu)建springboot項(xiàng)目時,速度較慢,用時比較長,為了加快構(gòu)建docker鏡像的速度,采用分層構(gòu)建的方式,這篇文章主要介紹了springboot項(xiàng)目docker分層構(gòu)建,需要的朋友可以參考下2024-03-03Java?Excel?Poi字體顏色自定義設(shè)置代碼
最近項(xiàng)目使用POI按模板導(dǎo)出Excel,需要設(shè)置單元格的字體為紅色,下面這篇文章主要給大家介紹了關(guān)于Java?Excel?Poi字體顏色自定義設(shè)置的相關(guān)資料,需要的朋友可以參考下2024-01-01MyBatis傳入?yún)?shù)的實(shí)例代碼
這篇文章主要介紹了MyBatis傳入?yún)?shù)的實(shí)例代碼的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-06-06Java如果通過jdbc操作連接oracle數(shù)據(jù)庫
這篇文章主要介紹了Java如果通過jdbc操作連接oracle數(shù)據(jù)庫,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-09-09Java OpenCV利用KNN算法實(shí)現(xiàn)圖像背景移除
這篇文章主要為大家介紹了Java OpenCV利用K最鄰近(KNN,K-NearestNeighbor)分類算法實(shí)現(xiàn)圖像背景移除的示例代碼,需要的可以參考一下2022-01-01