BeanFactory與FactoryBean,相信不少剛翻看Spring源碼的同窗跟我同樣很好奇這倆貨怎麼長得這麼像,分別都是幹啥用的。BeanFactory是Spring中Bean工廠的頂層接口,也是咱們常說的SpringIOC容器,它定下了IOC容器的一些規範和經常使用方法並管理着Spring中全部的Bean,今天咱們不講它,咱們看一下後面那個FactoryBean。html
先說下FactoryBean和其做用再開始分析:首先它是一個Bean,但又不只僅是一個Bean。它是一個能生產或修飾對象生成的工廠Bean,相似於設計模式中的工廠模式和裝飾器模式。它能在須要的時候生產一個對象,且不只僅限於它自身,它能返回任何Bean的實例。java
首發地址:https://www.guitu18.com/post/2019/04/28/33.htmlspring
上面的解釋有點抽象,那麼咱們瀏覽一遍FactoryBean在Spring中是怎麼應用的就好懂了。咱們都知道在Spring中咱們的Bean都會被Spring的IOC容器所管理,在AbstractApplicationContext中有一個很重要的方法:refresh(),項目啓動或重啓的時候refresh()會調用getBean()初始化全部的Bean,這個getBean()最終會指向AbstractBeanFactory中的getBean()方法。設計模式
在AbstractBeanFactory中,不論是根據名稱仍是根據類型,getBean()最終都會調用doGetBean(),在doGetBean()方法中一開始就獲取了名稱beanName和實例sharedInstance,這個方法太長,這裏就貼前面兩行。框架
String beanName = this.transformedBeanName(name); Object sharedInstance = this.getSingleton(beanName);
transformedBeanName(name)是爲了獲取Bean真正的名稱,它會去掉name前面的'&'
,而getSingleton(beanName)是從父類容器singletonObjects中取的這個Bean的實例。在Spring中還有不少這樣的容器,好比DefaultListableBeanFactory中的beanDefinitionMap,它就是的IOC容器真正保存Bean的地方,它是一個HashMap。相似的還有FactoryBeanRegistrySupport中的factoryBeanObjectCache等。ide
回到doGetBean()方法中,拿到sharedInstance後,後面的一大堆操做作了單例、多例等判斷,最終會走到this.getObjectForBeanInstance(),關鍵部分就在這個方法中,進入方法代碼。post
protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { if (BeanFactoryUtils.isFactoryDereference(name)) { if (beanInstance instanceof NullBean) { return beanInstance; } if (!(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(this.transformedBeanName(name), beanInstance.getClass()); } } if (beanInstance instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) { Object object = null; if (mbd == null) { object = this.getCachedObjectForFactoryBean(beanName); } if (object == null) { FactoryBean<?> factory = (FactoryBean)beanInstance; if (mbd == null && this.containsBeanDefinition(beanName)) { mbd = this.getMergedLocalBeanDefinition(beanName); } boolean synthetic = mbd != null && mbd.isSynthetic(); object = this.getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; } else { return beanInstance; } }
在上面的代碼中有兩個判斷分別是beanInstance instanceof FactoryBean
和BeanFactoryUtils.isFactoryDereference(name)
,前面判斷的是beanInstance是否屬於FactoryBean或其子類的實例,後面這個方法判斷name是否不爲空且以&
開頭。性能
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);
繼續跟蹤進去看代碼。測試
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) { if (factory.isSingleton() && this.containsSingleton(beanName)) { synchronized(this.getSingletonMutex()) { Object object = this.factoryBeanObjectCache.get(beanName); if (object == null) { object = this.doGetObjectFromFactoryBean(factory, beanName); Object alreadyThere = this.factoryBeanObjectCache.get(beanName); 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; } }
這裏面也是作了不少判斷,我們也只挑關鍵部分看。這裏說一下我的想法,看源碼的時候若是咱們一直追究全部的細節那會讓咱們會越陷越深,掉入細節的無底洞,稍不留神腦回路跟不上就會蒙圈。咱們要學會找源碼中的關鍵部分看,弄懂主要流程和本次看源碼的目的的那部分就行。等咱們對Spring總體有了一個很好的理解以後,再回頭看以前不懂的代碼就會豁然開朗。在上面這個方法中不論是走上面的if分支仍是到下邊的else中,關鍵部分就是object = this.doGetObjectFromFactoryBean(factory, beanName)
這段代碼調用,繼續點進去。ui
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的描述印證了,FactoryBean是一個能生產或修飾對象生成的工廠Bean。一個Bean若是實現了FactoryBean接口,那麼根據該Bean的名稱獲取到的其實是getObject()返回的對象,而不是這個Bean自身實例,若是要獲取這個Bean自身實例,那麼須要在名稱前面加上'&'符號。
通常狀況下,Spring經過反射機制利用
的class屬性指定實現類實例化Bean,在某些狀況下,實例化Bean過程比較複雜,若是按照傳統的方式,則須要在 中提供大量的配置信息。配置方式的靈活性是受限的,這時採用編碼的方式可能會獲得一個簡單的方案。Spring爲此提供了一個org.springframework.bean.factory.FactoryBean的工廠類接口,用戶能夠經過實現該接口定製實例化Bean的邏輯。FactoryBean接口對於Spring框架來講佔用重要的地位,Spring自身就提供了70多個FactoryBean的實現。它們隱藏了實例化一些複雜Bean的細節,給上層應用帶來了便利。從Spring3.0開始,FactoryBean開始支持泛型,即接口聲明改成FactoryBean 的形式
原理弄明白了,下面經過代碼測試驗證上面的流程,先定義一個Bean實現FactoryBean接口。
@Component public class MyBean implements FactoryBean { private String message; public MyBean() { this.message = "經過構造方法初始化實例"; } @Override public Object getObject() throws Exception { MyBean myBean = new MyBean(); myBean.message = "經過FactoryBean.getObject()建立實例"; // 這裏並不必定要返回MyBean自身的實例,能夠是其餘任何對象的實例 return myBean; } @Override public Class<?> getObjectType() { return MyBean.class; } public String getMessage() { return message; } }
MyBean實現了FactoryBean接口的兩個方法,getObject()是能夠返回任何對象的實例的,這裏測試就返回MyBean自身實例,且返回前給message字段賦值。同時在構造方法中也爲message賦值。而後測試代碼中先經過名稱獲取Bean實例,打印message的內容,再經過'&'+名稱獲取實例並打印message內容。
@RunWith(SpringRunner.class) @SpringBootTest(classes = TestApplication.class) public class FactoryBeanTest { @Autowired private ApplicationContext context; @Test public void test() { MyBean myBean1 = (MyBean) context.getBean("myBean"); System.out.println("myBean1 = " + myBean1.getMessage()); MyBean myBean2 = (MyBean) context.getBean("&myBean"); System.out.println("myBean2 = " + myBean2.getMessage()); System.out.println("myBean1.equals(myBean2) = " + myBean1.equals(myBean2)); } }
myBean1 = 經過FactoryBean.getObject()初始化實例 myBean2 = 經過構造方法初始化實例 myBean1.equals(myBean2) = false
經過測試咱們發現獲取的兩個實例中的message的值不同,對比兩個對象的引用也不相同。上述所講關於FactoryBean的內容印證完畢,本文結束。