天天看點

Spring系列之FactoryBean(一)

在我們的開發工作中應該都見過或使用過FactoryBean這個類,也許你會看成了BeanFactory這個類。FactoryBean和BeanFactory雖然長的很像,但是他們的作用确實完全不像。這裡你可以想象一下,你會在什麼樣的場景下使用FactoryBean這個接口?FactoryBean是一個工廠Bean,可以生成某一個類型Bean執行個體,它最大的一個作用是:可以讓我們自定義Bean的建立過程。BeanFactory是Spring容器中的一個基本類也是很重要的一個類,在BeanFactory中可以建立和管理Spring容器中的Bean,它對于Bean的建立有一個統一的流程。下面我們先看一下FactoryBean中有什麼東西:

從上面的代碼中我們發現在FactoryBean中定義了一個Spring Bean的很重要的三個特性:是否單例、Bean類型、Bean執行個體,這也應該是我們關于Spring中的一個Bean最直覺的感受。雖然沒有傳回BeanName的值,但是我們也知道BeanName的值。下面我們來寫一個關于FactoryBean的小例子,看看我們是怎麼使用FactoryBean的,然後再從源碼的角度看看Spring是怎麼解析FactoryBean中的Bean的。

我們的輸出結果如下:

從上面的代碼中我們可以看到我們從Spring容器中擷取了FactoryBeanService類型的Bean。那麼這個擷取Bean的過程Spring是怎麼處理的呢?它是怎麼從FactoryBean中擷取我們自己建立的Bean執行個體的呢?我們先從getBean這個方法看起,因為在Spring的AbstractApplicationContext中有很多重載的getBean方法,這裡我們調用的是根據Type(指Class類型)來擷取的Bean資訊。我們傳入的type是FactoryBeanService類型。

AbstractApplicationContext#getBean(java.lang.Class)

DefaultListableBeanFactory#getBean(java.lang.Class)

在上面的代碼中,我們重點關注的是resolveNamedBean這個方法:

在上面的代碼中我們說我們傳入的type是com.zkn.spring.learn.service.FactoryBeanService類型,但是在我們的Spring容器中卻沒有FactoryBeanService類型的Bean,那麼我們是怎麼從getBeanNamesForType擷取到beanName的呢?

getBeanNamesForType的分析

doGetBeanNamesForType的分析

在上面的代碼中,我們可以知道的是我們的FactoryBeanLearn是一個FactoryBean類型的類。是以在上面的代碼中會調用isTypeMatch這個方法來判斷FactoryBeanLearn是不是和我們傳入的類型相比對。這裡是值:FactoryBeanService類。我們去isTypeMatch方法中去看一下它是怎麼進行類型比對判斷的:由于isTypeMatch方法很長,這裡我們隻看和我們這次分析相關的一部分代碼

getTypeForFactoryBean

我們在調用factoryBeanLearn的getObjectType方法的時候,擷取到的值為:com.zkn.spring.learn.service.FactoryBeanService和我們傳入的type是一樣的類型。是以這裡傳回true,根據我們上面說的如果isTypeMatch傳回true的話,我們傳回的beanName為factoryBeanLearn。

上面的分析總結起來是:我們調用getBean(Class requiredType)方法根據類型來擷取容器中的bean的時候,對應我們的例子就是:根據類型com.zkn.spring.learn.service.FactoryBeanService來從Spring容器中擷取Bean(首先明确的一點是在Spring容器中沒有FactoryBeanService類型的BeanDefinition。但是卻有一個Bean和FactoryBeanService這個類型有一些關系)。Spring在根據type去擷取Bean的時候,會先擷取到beanName。擷取beanName的過程是:先循環Spring容器中的所有的beanName,然後根據beanName擷取對應的BeanDefinition,如果目前bean是FactoryBean的類型,則會從Spring容器中根據beanName擷取對應的Bean執行個體,接着調用擷取到的Bean執行個體的getObjectType方法擷取到Class類型,判斷此Class類型和我們傳入的Class是否是同一類型。如果是則傳回測beanName,對應到我們這裡就是:根據factoryBeanLearn擷取到FactoryBeanLearn執行個體,調用FactoryBeanLearn的getObjectType方法擷取到傳回值FactoryBeanService.class。和我們傳入的類型一緻,是以這裡擷取的beanName為factoryBeanLearn。換句話說這裡我們把factoryBeanLearn這個beanName映射為了:FactoryBeanService類型。即FactoryBeanService類型對應的beanName為factoryBeanLearn這是很重要的一點。在這裡我們也看到了FactoryBean中三個方法中的一個所發揮作用的地方。我們在下一篇文章中着重分析:getBean(String name, Class requiredType, Object... args)這個方法。