spring的factoryBean原理

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í)行工廠方法,有幾個點要注意

  1. 調(diào)用完工廠方法拿到對象后,并不是直接返回,還會調(diào)用BeanPostProcessor的postProcessAfterInitialization方法。spring內(nèi)置的幾個processor要執(zhí)行
  2. 會判斷工廠產(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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容