spring容器管理的bean中,有一種比較特殊的類型FactoryBean,這種類型的bean,自身即是一個bean對象,也能產(chǎn)生其他類型的bean對象,通過接口方法便可得知
//從工廠拿到bean對象
T getObject() throws Exception
//工廠產(chǎn)生bean的類型
Class<?> getObjectType()
//是否為單例的
default boolean isSingleton() {
return true;
}
為何需要FactoryBean來產(chǎn)生bean對象,而不是直接定義好呢,這個主要是在一些特殊的場景,比如bean對象的產(chǎn)生過程比較復雜,需要根據(jù)一些配置信息等等。
如何從容器中獲取一個bean對象?這是spring容器內(nèi)部的一個實現(xiàn)邏輯,其中主要有三個變量要注意區(qū)分
- name,外部要獲取bean對象傳入的名稱
- beanName,spring容器內(nèi)部維護的bean對應的beanName,通常情況下name與beanName是一樣的,除了FactoryBean的情況
- shareInstance ,beanName對應的bean實例
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
//這里主要是為了處理FactoryBean的場景
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
普通的bean,根據(jù)beanName獲取到的shareInstance對象就是最終要返回的對象,而FactoryBean就不太一樣了
例如:程序中定義了一個User對象,還有一個UserFactoryBean,User對象沒有注入到spring容器,UserFactoryBean注入了,然后UserFactoryBean的工廠方法getObject返回的是一個User對象。
那么,如果通過spring容器要獲取到UserFactoryBean自身的bean實例,傳入的name是&userFactoryBean,要獲取User的bean實例,傳入的name是userFactoryBean,若name傳的是user,那么會找不到bean對象,這個也很好理解,User是通過UserFactoryBean產(chǎn)生的,所以傳入userFactoryBean。
接下來看下spring源碼是如何處理這種情況的
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
//根據(jù)name判斷要獲取的bean是FactoryBean自身,還是其工廠方法產(chǎn)生的,判斷的依據(jù)就是name是否有&前綴
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
//假如beanInstance自身就是一個普通的bean對象,那么直接返回
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
//根據(jù)beanName獲取緩存中工廠方法產(chǎn)生的對象
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
//獲取工廠方法產(chǎn)生的bean對象,若是Singleton的,那么還會將對象緩存起來
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
這個方法邏輯很簡單,如果beanInstance是普通的bean,那么直接返回;如果是FactoryBean的話,那么根據(jù)name判斷程序是要獲取FactoryBean自身的bean實例,還是其工廠方法產(chǎn)生的bean實例。若是自身的,那么直接返回;若是要獲取工廠產(chǎn)生的,那么先看緩存有沒,有的話直接拿,沒有的話,再進入工廠方法創(chuàng)建bean。
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
beforeSingletonCreation(beanName);
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
這個方法不僅僅是執(zhí)行工廠方法,有幾個點要注意
- 調(diào)用完工廠方法拿到對象后,并不是直接返回,還會調(diào)用BeanPostProcessor的postProcessAfterInitialization方法。spring內(nèi)置的幾個processor要執(zhí)行
- 會判斷工廠產(chǎn)生的bean是否為singleton,若是的話,還會加入到factoryBeanObjectCache,這樣每次獲取到的bean就是單例的,不會重新走工廠方法來創(chuàng)建一個新對象。
以上就是從spring容器中獲取FactoryBean和其工廠產(chǎn)生的bean的邏輯,細心的可能會發(fā)現(xiàn),程序中有時并不是根據(jù)name來獲取bean,而是通過Class對象,那么如果通過class對象來獲取bean是如何處理的,跟蹤源碼會發(fā)現(xiàn),也是需要根據(jù)Class類型獲取到對應的name,再走上述講的邏輯。所以重點就看下如果通過Class獲取到name
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
List<String> result = new ArrayList<>();
// Check all bean definitions.
for (String beanName : this.beanDefinitionNames) {
// Only consider bean as eligible if the bean name is not defined as alias for some other bean.
if (!isAlias(beanName)) {
try {
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// Only check bean definition if it is complete.
if (!mbd.isAbstract() && (allowEagerInit ||
(mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&
!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
boolean isFactoryBean = isFactoryBean(beanName, mbd);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
boolean matchFound = false;
boolean allowFactoryBeanInit = (allowEagerInit || containsSingleton(beanName));
boolean isNonLazyDecorated = (dbd != null && !mbd.isLazyInit());
if (!isFactoryBean) {
if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) {
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
}
else {
if (includeNonSingletons || isNonLazyDecorated ||
(allowFactoryBeanInit && isSingleton(beanName, mbd, dbd))) {
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
if (!matchFound) {
// In case of FactoryBean, try to match FactoryBean instance itself next.
beanName = FACTORY_BEAN_PREFIX + beanName;
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
}
if (matchFound) {
result.add(beanName);
}
}
}
catch (CannotLoadBeanClassException | BeanDefinitionStoreException ex) {
}
catch (NoSuchBeanDefinitionException ex) {
}
}
}
//省略.......
return StringUtils.toStringArray(result);
}
這個方法的主要邏輯就是,循環(huán)spring容器的所有beanName,然后再根據(jù)isTypeMatch方法來判斷當前的Class類型是否能匹配上這個beanName,若是的話,會返回。
這里不管當前beanName對應的bean是否為FactoryBean,都走的是isTypeMatch方法。所以問題的關(guān)鍵就在這方法內(nèi)部,但是會發(fā)現(xiàn)如果isFactoryBean是true的話,可能需要執(zhí)行兩次isTypeMatch,這結(jié)合isTypeMatch方法邏輯便可知道了
protected boolean isTypeMatch(String name, ResolvableType typeToMatch, boolean allowFactoryBeanInit)
throws NoSuchBeanDefinitionException {
String beanName = transformedBeanName(name);
boolean isFactoryDereference = BeanFactoryUtils.isFactoryDereference(name);
// Check manually registered singletons.
Object beanInstance = getSingleton(beanName, false);
if (beanInstance != null && beanInstance.getClass() != NullBean.class) {
if (beanInstance instanceof FactoryBean) {
if (!isFactoryDereference) {
Class<?> type = getTypeForFactoryBean((FactoryBean<?>) beanInstance);
return (type != null && typeToMatch.isAssignableFrom(type));
}
else {
return typeToMatch.isInstance(beanInstance);
}
}
else if (!isFactoryDereference) {
if (typeToMatch.isInstance(beanInstance)) {
// Direct match for exposed instance?
return true;
}
這個方法比較長,只挑前面一部分代碼就可以大概的理解邏輯了
根據(jù)beanName獲取到bean對象,如果bean對象只是普通類型的,那么就直接對比對象是否為ResolvableType 的,若是則匹配成功(實際會復雜一些)
若bean對象是FactoryBean的,那么根據(jù)傳進來的name是否要獲取FactoryBean自身的,若是的話,也是直接比較(和普通類型的一樣)。若不是,說明要獲取的是工廠方法產(chǎn)生的bean,那么需要調(diào)用FactoryBean的getObjectType方法,來判斷工廠返回的類型能否匹配上ResolvableType