注意:這裏是
FactoryBean
,而不是BeanFactory
html
FactoryBean
是一個工廠Bean
,用於生成某一個類型Bean
實例BeanFactory
是Spring
容器中的一個基本類也是很重要的一個類,用於建立和管理Spring
容器中的Bean
FactoryBean
首先它是一個Bean
,但又不單單是一個Bean
。它是一個能生產或修飾對象生成的工廠Bean
,相似於設計模式中的工廠模式和裝飾器模式。它能在須要的時候生產一個對象,且不單單限於它自身,它能返回任何Bean
的實例。源碼以下:java
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
// 返回一個對象實例,這個對象會添加到容器中
@Nullable
T getObject() throws Exception;
// Bean的類型
@Nullable
Class<?> getObjectType();
// 控制是不是單例,返回true爲單例(容器中保存一份),返回false爲多例(每次獲取調用getObject()建立新的)
default boolean isSingleton() {
return true;
}
}
複製代碼
在
FactoryBean
接口中,有三個方法,使用的時候經過調用工廠Bean
獲取FactoryBean
的getObject
方法建立對象:spring
getObject()
:返回一個對象實例,這個對象會添加到容器中getObjectType()
:獲取Bean
的類型isSingleton()
:控制是不是單例,返回true爲單例(容器中保存一份),返回false爲多例(每次獲取調用getObject()
建立新的)
FactoryBean
做爲一個生產或修飾對象的工廠Bean
,那是如何生產Bean
的呢,我們經過實例來進行分析,這裏就使用工廠Bean
來生產Color
對象設計模式
// 啓動類
public class MainTest {
@Test
public void TestMain(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
String[] beanNames = applicationContext.getBeanDefinitionNames();
for (String beanName : beanNames) {
System.out.println(beanName);
}
// 工廠Bean獲取的是getObject建立的對象
Object factoryBean = applicationContext.getBean("colorFactoryBean");
System.out.println("Bean的類型" + factoryBean.getClass());
// 測試isSingleton控制單例多例
Object factoryBean2 = applicationContext.getBean("colorFactoryBean");
System.out.println("Bean的類型" + factoryBean.getClass());
System.out.println(factoryBean == factoryBean2);
// 經過加「&」獲取ColorFactoryBean對象
Object factoryBean3 = applicationContext.getBean("&colorFactoryBean");
System.out.println(factoryBean3.getClass());
}
}
// 待生產的Color對象
public class Color {
}
// 建立一個spring定義的工廠Bean
public class ColorFactoryBean implements FactoryBean {
// 返回一個color對象,這個對象會添加到容器中
public Object getObject() throws Exception {
return new Color();
}
// Bean的類型
public Class<?> getObjectType() {
return Color.class;
}
// 控制是不是單例,返回true爲單例(容器中保存一份),返回false爲多例(每次獲取調用getObject()建立新的)
public boolean isSingleton() {
return false;
}
}
// 配置類
@Configuration
public class AppConfig {
/** * 1.默認獲取的是工廠Bean調用getObject建立的對象 * 2.要獲取工廠Bean自己,須要給ID前面加一個「&」 */
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}
}
複製代碼
運行啓動類,能夠看到,已經將Bean對象給生產出來了,根據打印信息,能夠得出如下結論:緩存
Bean
獲取的是getObject
所建立的對象,這也就是所謂的生產Bean
isSingleton
方法返回值能夠改變建立Bean
的單例仍是多例FactoryBean
自己注入進spring
容器中,獲取的時候須要給ID前面加一個「&」參考:www.cnblogs.com/guitu18/p/1…markdown
FactoryBean
是怎麼讓Spring
容器管理調用它的getObject
所生成的Bean
的,我們經過源碼來看看FactorBean
是如何生產Bean
的,app
在啓動類中經過調用:AnnotationConfigApplicationContext
——> refresh()
方法——> getBean()
方法,再到AbstractBeanFactory
實現類,在這個類中,又調用了doGetBean
方法,doGetBean
能夠說是Spring
容器中一個很核心的一個類,裏面的功能不少很複雜,咱們在這篇文章中只關注和FactoryBean
相關的內容。截取部分代碼:oop
【1】doGetBean
方法中調用getSingleton
方法 從Spring容器中獲取單例Beanpost
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
String beanName = this.transformedBeanName(name);
// 調用getSingleton方法 從Spring容器中獲取單例Bean
Object sharedInstance = this.getSingleton(beanName);
Object bean;
if (sharedInstance != null && args == null) {
if (this.logger.isTraceEnabled()) {
if (this.isSingletonCurrentlyInCreation(beanName)) {
this.logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
} else {
this.logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
}
....
}
複製代碼
getSingleton
從Spring容器中獲取單例Bean性能
@Nullable
public Object getSingleton(String beanName) {
return this.getSingleton(beanName, true);
}
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 先從singletonObjects中獲取單例Bean singletonObjects是一個ConcurrentHashMap
// key是beanName value是單例Bean
Object singletonObject = this.singletonObjects.get(beanName);
// 若是沒有獲取到,則判斷是否是當前在建立中的單例Bean
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized(this.singletonObjects) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
複製代碼
【2】doGetBean
方法中調用getObjectForBeanInstance
,關鍵代碼就從這裏開始,查看源碼:
protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 這裏判斷 name是否是以&開頭,不是通過處理的beanName 而且這個bean實例 不是FactoryBean類型的
// 若是是&開頭而且不是FactoryBean類型 則拋出異常
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
// 不是FactoryBean類型 或者name以&開頭 直接返回bean實例,要根據beanName獲取真正的FactoryBean實例的時候,在beanName前面加上&
} else if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
} else {
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
} else if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
} else {
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
} else {
// factoryBeanObjectCache 看看是否是在緩存中存在
object = this.getCachedObjectForFactoryBean(beanName);
}
// 若是沒有
if (object == null) {
// 若是能走到這裏來 這個bean實例是FactoryBean類型的
FactoryBean<?> factory = (FactoryBean)beanInstance;
if (mbd == null && this.containsBeanDefinition(beanName)) {
mbd = this.getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = mbd != null && mbd.isSynthetic();
//從這個方法的名字咱們能夠看到這個方法的意思是:從FactoryBean中獲取對象
object = this.getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
}
複製代碼
分析以下:
- 第一個判斷
BeanFactoryUtils.isFactoryDereference
:判斷name是否不爲空且以&
開頭,若是是&開頭而且不是FactoryBean類型 則拋出異常- 後面的判斷
beanInstance instanceof FactoryBean
:不是FactoryBean
類型 或者name以&開頭 直接返回bean實例,要根據beanName獲取真正的FactoryBean
實例的時候,在beanName前面加上&
public static boolean isFactoryDereference(@Nullable String name) {
return name != null && name.startsWith("&");
}
複製代碼
若是beanInstance不屬於FactoryBean或其子類的實例,或者name是以&
開頭就直接返回實例對象beanInstance,不然進入到if分支中。在if分支裏的各類if .. ==null
判斷是爲了提升性能,我們只挑關鍵部分看:object = this.getObjectFromFactoryBean(factory, beanName, !synthetic);
繼續跟蹤進去看代碼。
【3】getObjectFromFactoryBean
調用doGetObjectFromFactoryBean
方法
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
// FactoryBean類型的實例 調用isSingleton方法返回的是true,所傳入的bean實例也要求是單例類型的
if (factory.isSingleton() && this.containsSingleton(beanName)) {
synchronized(this.getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 調用doGetObjectFromFactoryBean方法從FactoryBean中獲取bean對象,這裏是調用的FactoryBean的getObject方法來獲取的
object = this.doGetObjectFromFactoryBean(factory, beanName);
// 再從緩存中獲取一次
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
// 若是上一步的緩存中獲取到了則用緩存中的替代咱們從FactoryBean中獲取的bean
if (alreadyThere != null) {
object = alreadyThere;
} else {
if (shouldPostProcess) {
if (this.isSingletonCurrentlyInCreation(beanName)) {
return object;
}
this.beforeSingletonCreation(beanName);
try {
object = this.postProcessObjectFromFactoryBean(object, beanName);
} catch (Throwable var14) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's singleton object failed", var14);
} finally {
this.afterSingletonCreation(beanName);
}
}
if (this.containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
} else {
Object object = this.doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = this.postProcessObjectFromFactoryBean(object, beanName);
} catch (Throwable var17) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", var17);
}
}
return object;
}
}
複製代碼
分析:
factory.isSingleton() && this.containsSingleton(beanName)
判斷就是調用isSingleton方法返回的是true,也就是對用實例中經過isSingleton
方法返回true來控制單例this.doGetObjectFromFactoryBean(factory, beanName)
:調用doGetObjectFromFactoryBean
方法從FactoryBean
中獲取bean對象,這裏是調用的FactoryBean
的getObject方法來獲取的
【4】調用doGetObjectFromFactoryBean
方法
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = this.getAccessControlContext();
try {
object = AccessController.doPrivileged(factory::getObject, acc);
} catch (PrivilegedActionException var6) {
throw var6.getException();
}
} else {
object = factory.getObject();
}
} catch (FactoryBeanNotInitializedException var7) {
throw new BeanCurrentlyInCreationException(beanName, var7.toString());
} catch (Throwable var8) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", var8);
}
if (object == null) {
if (this.isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
複製代碼
分析:
- object = factory.getObject():這個factory就是咱們傳入的
beanInstance
實例。繞了這麼一大圈,getBean方法返回的竟然是咱們實現FactoryBean接口定義的getObject方法
到這裏,就證明了案例中的結論了:FactoryBean是一個能生產或修飾對象生成的工廠Bean。一個Bean若是實現了FactoryBean接口,那麼根據該Bean的名稱獲取到的其實是getObject()返回的對象,而不是這個Bean自身實例,若是要獲取這個Bean自身實例,那麼須要在名稱前面加上'&'符號。