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返回的對(duì)象。但我們可以通過其它途徑獲取到該FactoryBean的實(shí)例,方法就是在通過getBean方法獲取實(shí)例時(shí)在參數(shù)name前面加上“&”符號(hào)即可。
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>
測(cè)試代碼
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對(duì)象實(shí)例,通過&myFactoryBean獲取到的是MyFactoryBean對(duì)象實(shí)例。

4、實(shí)現(xiàn)原理
我們來看一下執(zhí)行Date now = (Date) appCtx.getBean("myFactoryBean"); 時(shí)會(huì)做的處理操作。 AbstractBeanFactory中會(huì)進(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中會(huì)選擇bean實(shí)例是普通的Bean還是FactoryBean,同時(shí)通過判斷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接下來會(huì)執(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對(duì)FactoryBean的實(shí)現(xiàn)機(jī)制是當(dāng)你獲取一個(gè)Bean時(shí),如果獲取的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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring中的BeanFactory與FactoryBean區(qū)別詳解
- SpringBoot升級(jí)3.2報(bào)錯(cuò)Invalid value type for attribute ‘factoryBeanObjectType‘: java.lang.String的解決方案
- Spring中的FactoryBean與ObjectFactory詳解
- Spring中BeanFactory與FactoryBean的區(qū)別解讀
- Spring中的FactoryBean與BeanFactory詳細(xì)解析
- Spring的FactoryBean<Object>接口示例代碼
- 簡(jiǎn)單了解Spring中BeanFactory與FactoryBean的區(qū)別
相關(guān)文章
Java fastjson解析json字符串實(shí)現(xiàn)過程解析
這篇文章主要介紹了Java fastjson解析json字符串實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10
springboot項(xiàng)目docker分層構(gòu)建的配置方式
在使用dockerfile構(gòu)建springboot項(xiàng)目時(shí),速度較慢,用時(shí)比較長(zhǎng),為了加快構(gòu)建docker鏡像的速度,采用分層構(gòu)建的方式,這篇文章主要介紹了springboot項(xiàng)目docker分層構(gòu)建,需要的朋友可以參考下2024-03-03
Java?Excel?Poi字體顏色自定義設(shè)置代碼
最近項(xiàng)目使用POI按模板導(dǎo)出Excel,需要設(shè)置單元格的字體為紅色,下面這篇文章主要給大家介紹了關(guān)于Java?Excel?Poi字體顏色自定義設(shè)置的相關(guān)資料,需要的朋友可以參考下2024-01-01
MyBatis傳入?yún)?shù)的實(shí)例代碼
這篇文章主要介紹了MyBatis傳入?yún)?shù)的實(shí)例代碼的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-06-06
Java如果通過jdbc操作連接oracle數(shù)據(jù)庫(kù)
這篇文章主要介紹了Java如果通過jdbc操作連接oracle數(shù)據(jù)庫(kù),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
Java OpenCV利用KNN算法實(shí)現(xiàn)圖像背景移除
這篇文章主要為大家介紹了Java OpenCV利用K最鄰近(KNN,K-NearestNeighbor)分類算法實(shí)現(xiàn)圖像背景移除的示例代碼,需要的可以參考一下2022-01-01

