Spring源碼(四)-FactoryBean與getBean

上一篇講到了BeanFactory,那就不得不提一下FactoryBean,先看一下它的定義吧!

定義

public interface FactoryBean<T> {

    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
    //返回的對(duì)象實(shí)例
    @Nullable
    T getObject() throws Exception;

     //返回對(duì)象類型
    @Nullable
    Class<?> getObjectType();

   //getObject返回的對(duì)象是否單例。true代表單例,false代表非單例
    default boolean isSingleton() {
        return true;
    }
}

看到里面的三個(gè)方法名,我們可以見(jiàn)名知意了。Bean實(shí)例、Bean類型、bean是否單例。那接下來(lái)我們就實(shí)現(xiàn)FactoryBean 接口,看看是怎么使用 FactoryBean 的,然后再?gòu)脑创a的角度去看看 Spring 是怎么解析FactoryBean 中的 Bean 的。


實(shí)踐

GongjFactoryBean

GongjFactoryBean 實(shí)現(xiàn) FactoryBean ,并重寫其三個(gè)方法。

@Component
public class GongjFactoryBean implements FactoryBean {

    /**
     * 當(dāng)該Bean是單例時(shí),該方法只執(zhí)行一次
     * @return
     * @throws Exception
     */
    @Override
    public Object getObject() throws Exception {
        User user = new User();
        System.out.println("====" + user);
        return user;
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }

    /**
     * 可以控制該Bean的作用域是單例還是原型
     * @return
     */
    @Override
    public boolean isSingleton() {
        return true;
    }
}

AppConfig

新建AppConfig作為啟動(dòng)掃描類

@ComponentScan("com.gongj")
public class AppConfig {
}

Main

使用 AnnotationConfigApplicationContext 容器啟動(dòng) Spring

public class Main {
    public static void main(String[] args) {
        //啟動(dòng)spring容器  ----> 創(chuàng)建非懶加載的單例Bean
        //掃描包路徑
        AnnotationConfigApplicationContext annotationConfigApplicationContext =
                new AnnotationConfigApplicationContext(AppConfig.class);
  
System.out.println(annotationConfigApplicationContext.getBean("gongjFactoryBean"));     System.out.println(annotationConfigApplicationContext.getBean("gongjFactoryBean"));
System.out.println(annotationConfigApplicationContext.getBean("&gongjFactoryBean"));
System.out.println(annotationConfigApplicationContext.getBean("&gongjFactoryBean"));
    }
}

啟動(dòng)main方法輸出以下結(jié)果:

====com.gongj.entity.User@cac736f  #這是我在GongjFactoryBean中進(jìn)行打印的
com.gongj.entity.User@cac736f
com.gongj.entity.User@cac736f
com.gongj.service.GongjFactoryBean@5e265ba4
com.gongj.service.GongjFactoryBean@5e265ba4

通過(guò)上面啟動(dòng)的這個(gè)例子我們可以得出以下幾個(gè)結(jié)論:

  • GongjFactoryBean#getObject()函數(shù)只執(zhí)行一次
  • 根據(jù) gongjFactoryBean 獲取的是 User 對(duì)象并每次獲取的 User 對(duì)象一致。
  • 根據(jù) &gongjFactoryBean 獲取的是 GongjFactoryBean 對(duì)象并每次獲取的 GongjFactoryBean 對(duì)象一致。

初步懷疑該現(xiàn)象是 isSingleton 函數(shù)進(jìn)行控制的。那我接下來(lái)將isSingleton函數(shù)返回的值修改為false

@Override
    public boolean isSingleton() {
        return false;
    }

再次執(zhí)行main方法,輸出以下結(jié)果:

====com.gongj.entity.User@cac736f  #這是我在GongjFactoryBean中進(jìn)行打印的
com.gongj.entity.User@cac736f
====com.gongj.entity.User@5e265ba4  #這是我在GongjFactoryBean中進(jìn)行打印的
com.gongj.entity.User@5e265ba4
com.gongj.service.GongjFactoryBean@156643d4
com.gongj.service.GongjFactoryBean@156643d4

通過(guò)上面啟動(dòng)的這個(gè)例子我們又可以得出以下幾個(gè)結(jié)論:

  • isSingleton() 函數(shù)控制的是以 gongjFactoryBean 獲取的對(duì)象是否是單例的。
  • isSingleton() 函數(shù)的修改不影響以 &gongjFactoryBean 獲取的對(duì)象,它還是單例的。

看到這我們應(yīng)該就有疑惑了,讓我們帶著疑惑開始一步一步DEGUG源碼。

將 isSingleton() 函數(shù)的返回值修改為true。


image.png

根據(jù)上圖我們可以得出結(jié)論:

  • GongjFactoryBean 在啟動(dòng)的時(shí)候就已經(jīng)加入到 Spring 容器中。很顯然 GongjFactoryBean 是一個(gè)非懶加載的單例 Bean。

調(diào)試

  • 進(jìn)入AbstractApplicationContext#getBean
@Override
    public Object getBean(String name) throws BeansException {
        assertBeanFactoryActive();
        return getBeanFactory().getBean(name);  》》
    }
  • AbstractBeanFactory#getBean
@Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false); 》》
    }
  • AbstractBeanFactory#doGetBean
    protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

        // 對(duì)beanName進(jìn)行轉(zhuǎn)換 name如果是"&gongjFactoryBean",那么beanName就是"gongjFactoryBean"
        final String beanName = transformedBeanName(name); 》》
        Object bean;

        //根據(jù)beanName去單例池中獲取單例Bean
        Object sharedInstance = getSingleton(beanName);  》》
        if (sharedInstance != null && args == null) {
              //.....省略代碼
            // 判斷sharedInstance是不是FactoryBean,
            // 如果是FactoryBean,那么真正需要拿到的是getObject方法所返回的對(duì)象
            //beanName 是spinrg進(jìn)行解析后獲取到的BeanName  
            //name 我們手動(dòng)傳入的beanName
            //sharedInstance 根據(jù)beanName獲取到的單例Bean對(duì)象
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);  》》
        }

       else{
          //....省略代碼 下篇分析
       }
}
  • AbstractBeanFactory#transformedBeanName
    先調(diào)用 BeanFactoryUtils.transformedBeanName方法,然后拿到返回值,再執(zhí)行canonicalName方法。
//返回beanName,去掉傳入name的&前綴,并且把返回的name當(dāng)做別名去aliasMap中尋找原始的beanName
protected String transformedBeanName(String name) { 
        return canonicalName(BeanFactoryUtils.transformedBeanName(name));
    }
  • BeanFactoryUtils#transformedBeanName
private static final Map<String, String> transformedBeanNameCache = new ConcurrentHashMap<>();
String FACTORY_BEAN_PREFIX = "&";

public static String transformedBeanName(String name) {
        Assert.notNull(name, "'name' must not be null");
        // 如果beanName沒(méi)有以&開頭,則直接返回
        if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {   // gongjFactoryBean
            return name;
        }
        // 如果beanName以&開頭,截取&后的beanName,并且把截取前后的name存在transformedBeanNameCache 中
//可能會(huì)有多個(gè)&&&,循環(huán)截取
        return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
            do {
                beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
            }
            while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
            return beanName;
        });
    }
  • SimpleAliasRegistry#canonicalName
private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);

public String canonicalName(String name) {
        String canonicalName = name;
        String resolvedName;
        do {
//根據(jù)傳遞過(guò)來(lái)的beanName,去別名Map中查找  獲取出來(lái)就是真正的BeanName  例如:gjfg = gongjFactoryBean
            resolvedName = this.aliasMap.get(canonicalName); 
            if (resolvedName != null) {
                canonicalName = resolvedName;
            }
        }
        while (resolvedName != null);
        return canonicalName;
    }

transformedBeanName 方法到此結(jié)束!


  • getSingleton

再來(lái)看一下 Spring 是如何根據(jù) beanName 去單例池中獲取單例Bean

@Override
    @Nullable
    public Object getSingleton(String beanName) {
        return getSingleton(beanName, true);
    }
@Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // 從單例池中獲取實(shí)例  singletonObjects 一級(jí)緩存
        Object singletonObject = this.singletonObjects.get(beanName);

        // 如果從單例池中沒(méi)有獲取到實(shí)例 并且指定的單例bean正在創(chuàng)建中
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        //鎖定全局變量并進(jìn)行處理
            synchronized (this.singletonObjects) {
                //earlySingletonObjects 二級(jí)緩存
                singletonObject = this.earlySingletonObjects.get(beanName);
                // 沒(méi)有從二級(jí)緩存中獲取到
                if (singletonObject == null && allowEarlyReference) {
                    //當(dāng)某些方法需要提前初始化的時(shí)候,會(huì)調(diào) addSingletonFactory 方法將對(duì)
                    //ObjectFactory 初始化存儲(chǔ)在 singletonFactories Map中
                    // singletonFactories 三級(jí)緩存
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        singletonObject = singletonFactory.getObject(); 
//記錄在緩存中 earlySingletonObjects與singletonFactories互斥
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return singletonObject;
    }

這個(gè)方法首先嘗試從 singletonObjects(一級(jí)緩存) 里面獲取實(shí)例,如果取不到再?gòu)?code>earlySingletonObjects(二級(jí)緩存) 里面獲取,如果還獲取不到,再嘗試從 singletonFactories(三級(jí)緩存) 里面獲取 beanName 對(duì)應(yīng)的 ObjectFactory,然后調(diào)用這個(gè) ObjectFactory 的 getObject 方法來(lái)獲取 bean ,并放到 earlySingletonObjects(二級(jí)緩存) 里面 ,并且從singletonFacotories(三級(jí)緩存) 里面 remove 掉這個(gè) ObjectFactorγ。

  • singletonObjects :?jiǎn)卫龑?duì)象的緩存:Bean名稱到Bean實(shí)例,也就是常說(shuō)的單例池(一級(jí)緩存)。
  • singletonFacotories :?jiǎn)卫S的緩存(三級(jí)緩存), Bean名稱到ObjectFactory,一旦最終對(duì)象被創(chuàng)建(通過(guò)objectFactory.getObject()),此引用信息將刪除
  • earlySingletonObjects :用于存儲(chǔ)在創(chuàng)建Bean早期對(duì)創(chuàng)建的原始bean的一個(gè)引用(二級(jí)緩存),注意這里是原始bean,即使用工廠方法或構(gòu)造方法創(chuàng)建出來(lái)的對(duì)象,一旦對(duì)象最終創(chuàng)建好,此引用信息將刪除

getSingleton 方法到此結(jié)束!


  • AbstractBeanFactory#getObjectForBeanInstance
    關(guān)鍵部分就在這個(gè)方法中,進(jìn)入方法代碼
protected Object getObjectForBeanInstance(
            Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

        // name也就是我傳入的beanName 如果是以&符號(hào)開頭,則直接返回單例池(SingletonObjects)中的對(duì)象
        if (BeanFactoryUtils.isFactoryDereference(name)) {
            if (beanInstance instanceof NullBean) {
                return beanInstance;
            }
//判斷單例對(duì)象beanInstance是否實(shí)現(xiàn)了FactoryBean,如果沒(méi)有拋出異常
            if (!(beanInstance instanceof FactoryBean)) {
                throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
            }
            if (mbd != null) {
                mbd.isFactoryBean = true;
            }
            // 返回單例池(SingletonObjects)中的對(duì)象
            return beanInstance;
        }

        // 如果 beanInstance 不是 FactoryBean,則直接返回
        if (!(beanInstance instanceof FactoryBean)) {
            return beanInstance;
        }

        Object object = null;
        if (mbd != null) {
            mbd.isFactoryBean = true;
        }
        else {
//根據(jù)真正的BeanName從factoryBeanObjectCache緩存中獲取Bean對(duì)象
            object = getCachedObjectForFactoryBean(beanName);
        }

        // 從factoryBeanObjectCache中沒(méi)有拿到則進(jìn)行創(chuàng)建
        if (object == null) {
            FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
//從beanDefinitionMap判斷該Bean是否存在
            if (mbd == null && containsBeanDefinition(beanName)) {
//進(jìn)行Bean合并
                mbd = getMergedLocalBeanDefinition(beanName); 
            }
//是否是用戶定義的而不是應(yīng)用程序本身定義的
            boolean synthetic = (mbd != null && mbd.isSynthetic());
            // 調(diào)用getObject方法得到對(duì)象
            object = getObjectFromFactoryBean(factory, beanName, !synthetic); 》》
        }
        return object;
    }
  • FactoryBeanRegistrySupport#getObjectFromFactoryBean
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
        // 是不是單例的 && 根據(jù) beanName 判斷該名稱在 singletonObjects(單例池) 中是否存在
        if (factory.isSingleton() && containsSingleton(beanName)) {
            synchronized (getSingletonMutex()) {
                Object object = this.factoryBeanObjectCache.get(beanName);
                if (object == null) {
                    // 調(diào)用getObject方法得到一個(gè)對(duì)象
                    object = doGetObjectFromFactoryBean(factory, beanName); 》》
                    //再?gòu)木彺嬷蝎@取一遍
                    Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                    if (alreadyThere != null) {
                        object = alreadyThere;
                    }
                    else {
                        if (shouldPostProcess) {
                            //返回指定的單例bean當(dāng)前是否正在創(chuàng)建中
                            if (isSingletonCurrentlyInCreation(beanName)) {
                                return object;
                            }
                          //表示這些bean正常創(chuàng)建中,在沒(méi)創(chuàng)建完時(shí)不能重復(fù)創(chuàng)建
                            beforeSingletonCreation(beanName);
                            try {
                                // 調(diào)用BeanPostProcessor執(zhí)行初始化后的邏輯,主要就是進(jìn)行AOP
                                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)) {
                        //將創(chuàng)建的Bean放入factoryBeanObjectCache
                            this.factoryBeanObjectCache.put(beanName, object);
                        }
                    }
                }
                return object;
            }
        }
        else {
            // 多例 每次都創(chuàng)建一個(gè),不從factoryBeanObjectCache中獲取
            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;
        }
    }
  • FactoryBeanRegistrySupport#doGetObjectFromFactoryBean
    doGetObjectFromFactoryBean 方法中我們終于看到了我們想要看到的方法,也就是 object = factory.getObject();
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
            throws BeanCreationException {

        Object object;
        try {
            if (System.getSecurityManager() != null) {
                AccessControlContext acc = getAccessControlContext();
                try {
                    object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
                }
                catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            }
            else {
      //調(diào)用了FectoryBean里的getObject()函數(shù)
                object = factory.getObject();
            }
        }
        catch (FactoryBeanNotInitializedException ex) {
            throw new BeanCurrentlyInCreationException(beanName, ex.toString());
        }
        catch (Throwable ex) {
            throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
        }
        // 如果調(diào)用getObject()方法返回的是null,那么則返回一個(gè)NullBean
        if (object == null) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(
                        beanName, "FactoryBean which is currently in creation returned null from getObject");
            }
            object = new NullBean();
        }
        return object;
    }

到此,FactoryBean 就結(jié)束啦!當(dāng)然 getBean 方法才看到冰山一角。

FactoryBean是一個(gè)能生產(chǎn)或修飾對(duì)象生成的工廠 Bean。一個(gè) Bean 如果實(shí)現(xiàn)了 FactoryBean 接口,那么根據(jù)該 Bean 的名稱獲取到的實(shí)際上是 getObject()返回的對(duì)象,而不是這個(gè) Bean 自身實(shí)例,如果要獲取這個(gè)Bean自身實(shí)例,那么需要在名稱前面加上'&'符號(hào)。

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

相關(guān)閱讀更多精彩內(nèi)容

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