FactoryBean源碼解析

1、FactoryBean和BeanFactory的區(qū)別

BeanFactory,就是bean的工廠急鳄,主要是通過定位、加載乐导、注冊以及實(shí)例化來維護(hù)對象與對象之間的依賴關(guān)系典阵,以此來管理bean

FactoryBean奋渔,bean的一種,顧名思義壮啊,它也可以用來生產(chǎn)bean嫉鲸,也實(shí)現(xiàn)了相應(yīng)的工廠方法。

一般來說歹啼,Bean是由BeanFactory生產(chǎn)玄渗,但FactoryBean的特殊之處就在于它也能生產(chǎn)bean。

獲取FactoryBean的方法是getBean("&"+beanName);

   就是在beanName加個(gè)"&"前綴狸眼,若直接getBean(beanName),獲取到的是FactoryBean通過getObject接口生成的Bean藤树。見代碼:

Car

public class Car {

    private int maxSpeed;
    private String brand;
    private double price;

    public int getMaxSpeed() {
        return maxSpeed;
    }

    public void setMaxSpeed(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }
}

CarFactoryBean:

public class CarFactoryBean implements FactoryBean<Car> {

    private String carInfo;

    @Override
    public Car getObject() throws Exception {
        Car car = new Car () ;

        String [] infos = carInfo .split ( "," ) ;

        car.setBrand ( infos [ 0 ]) ;
        car.setMaxSpeed ( Integer.valueOf ( infos [ 1 ])) ;

        car.setPrice ( Double.valueOf ( infos [ 2 ])) ;
        return car;
    }

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

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

    public String getCarInfo() {
        return carInfo;
    }

    public void setCarInfo(String carInfo) {
        this.carInfo = carInfo;
    }
}

bean配置:

<bean id="car" class="com.wl.service.factorybean.CarFactoryBean" >
    <property name="carInfo" value="超級跑車,200,20000000"/>
</bean>

測試:

ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:applicationContext.xml");
Object car =  context.getBean("car");
Object carFactoryBean = context.getBean("&car");
System.out.println(car);
System.out.println(carFactoryBean);

結(jié)果為:

com.wl.service.factorybean.Car@13805618
com.wl.service.factorybean.CarFactoryBean@56ef9176

經(jīng)過上面的測試可以知道,通過“&”前綴可以獲取到FactoryBean拓萌,不加前綴獲取到的則是普通的bean岁钓。

2、factoryBean的源碼走讀

public interface FactoryBean<T> {  
   @Nullable
   T getObject() throws Exception;

   @Nullable
   Class<?> getObjectType();

   default boolean isSingleton() {
      return true;
   }

}

實(shí)現(xiàn)該接口的類需要實(shí)現(xiàn)以上的方法微王,其中g(shù)etObject就是用來生產(chǎn)bean的方法屡限。

通過AbstractBeanFactory.doGetBean可以知道,不論是單例還是原型的實(shí)例對象炕倘,最終都要通過getObjectForBeanInstance進(jìn)行轉(zhuǎn)換钧大,最終得到的才是符合要求的bean實(shí)例。如:

// Create bean instance.
//單例的處理
//首先創(chuàng)建beanFactory,即ObjectBeanFacotry并實(shí)現(xiàn)getObject接口
if (mbd.isSingleton()) {
   sharedInstance = getSingleton(beanName, () -> {
      try {
         return createBean(beanName, mbd, args);
      }
      catch (BeansException ex) {
         // Explicitly remove instance from singleton cache: It might have been put there
         // eagerly by the creation process, to allow for circular reference resolution.
         // Also remove any beans that received a temporary reference to the bean.
         destroySingleton(beanName);
         throw ex;
      }
   });
   bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

進(jìn)入到getObjectForBeanInstance

protected Object getObjectForBeanInstance(
        Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

    //進(jìn)行類型檢測罩旋,如果是&作為前綴拓型,但是傳入beanInstance不是FactoryBean類型的,則拋出異常
    if (BeanFactoryUtils.isFactoryDereference(name)) {
        if (beanInstance instanceof NullBean) {
            return beanInstance;
        }
        if (!(beanInstance instanceof FactoryBean)) {
            throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
        }
    }

    // Now we have the bean instance, which may be a normal bean or a FactoryBean.
    // If it's a FactoryBean, we use it to create a bean instance, unless the
    // caller actually wants a reference to the factory.
    //如果是非FactoryBean或者是&作為前綴的前綴瘸恼,則返回實(shí)例對象劣挫,無需轉(zhuǎn)換
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
        return beanInstance;
    }

    //需要轉(zhuǎn)換,說明輸入的name獲取的bean是需要調(diào)用FactoryBean的getObject
    //也就是說东帅,beanInstance是FactoryBean類型压固,同時(shí)name不是以&作為前綴
    //舉個(gè)例子:
    //<bean id="car" class="com.wl.service.factorybean.CarFactoryBean" >
    //  <property name="carInfo" value="超級跑車,200,20000000"/>
    //</bean>
    //這里輸入getBean("car"),首先beanInstance為CarFactoryBean,則需要通過CarFactoryBean.getObject進(jìn)行轉(zhuǎn)換
    Object object = null;
    if (mbd == null) {
        //先到FactoryBean生產(chǎn)bean對象的緩存中去取靠闭,如果沒有的話則用factorybean去生產(chǎn)一個(gè)
        object = getCachedObjectForFactoryBean(beanName);
    }
    if (object == null) {
        // Return bean instance from factory.
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        // Caches object obtained from FactoryBean if it is a singleton.
        if (mbd == null && containsBeanDefinition(beanName)) {
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        //通過factoryBean去生產(chǎn)bean
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
}

通過這個(gè)方法我們可以得出以下幾點(diǎn):

1)getObjectForBeanInstance這個(gè)方法通過輸入的beanInstance的有這么幾種情況:

beanInstance name getBean
instance of FactoryBean為true 非“&”前綴 拋出異常
instance of FactoryBean為false 非“&”前綴 返回beanInstance
instance of FactoryBean為true “&”前綴 返回beanInstance同時(shí)也是FactoryBean
instance of FactoryBean為true 非“&”前綴 先通過getCachedObjectForFactoryBean去緩存取該對象帐我,如果沒有表示第一次獲取,通過FactoryBean生成

3愧膀、factoryBean的源碼深入走讀

首先拦键,假如現(xiàn)在要獲取的是FactoryBean生成的bean實(shí)例,那么首先檩淋,會(huì)去緩存中取這個(gè)bean

Object object = null;
if (mbd == null) {
   //先到FactoryBean生產(chǎn)bean對象的緩存中去取芬为,如果沒有的話則用factorybean去生產(chǎn)一個(gè)
   object = getCachedObjectForFactoryBean(beanName);
}

進(jìn)入到getCachedObjectForFactoryBean萄金,是FactoryBeanRegistrySupport的方法

/** Cache of singleton objects created by FactoryBeans: FactoryBean name --> object */
/** 由factoryBean生成的單例bean都會(huì)緩存到factoryBeanObjectCache*/
private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);

protected Object getCachedObjectForFactoryBean(String beanName) {
        return this.factoryBeanObjectCache.get(beanName);
}

假如獲取不到,則生成對應(yīng)的FactoryBean媚朦,然后通過FactoryBean去生成

if (object == null) {
   //獲取對應(yīng)的FactoryBean
   FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
   //......省略
   //通過factoryBean去生產(chǎn)bean
   object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}

進(jìn)入到getObjectFromFactoryBean,是FactoryBeanRegistrySupport的方法

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) {
                //通過factory.getObject獲取
                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)) {
                        //將獲取到的對象放到factoryBeanObjectCache單例緩存map進(jìn)行存儲(chǔ)
                        this.factoryBeanObjectCache.put(beanName, object);
                    }
                }
            }
            return object;
        }
    }
    else {
        //非單例的處理氧敢,直接通過factory.getObejct獲取,然后再返回給用戶
        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;
    }
}

無論是單例和非單例询张,都會(huì)調(diào)用doGetObjectFromFactoryBean方法孙乖,看來此方法,就是生成bean對象的方法:

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 {
         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);
   }

   // Do not accept a null value for a FactoryBean that's not fully
   // initialized yet: Many FactoryBeans just return null then.
   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é)束唯袄。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蜗帜,隨后出現(xiàn)的幾起案子恋拷,更是在濱河造成了極大的恐慌,老刑警劉巖钮糖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件梅掠,死亡現(xiàn)場離奇詭異酌住,居然都是意外死亡店归,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門酪我,熙熙樓的掌柜王于貴愁眉苦臉地迎上來消痛,“玉大人,你說我怎么就攤上這事都哭≈壬。” “怎么了?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵欺矫,是天一觀的道長纱新。 經(jīng)常有香客問我,道長穆趴,這世上最難降的妖魔是什么脸爱? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮未妹,結(jié)果婚禮上簿废,老公的妹妹穿的比我還像新娘。我一直安慰自己络它,他們只是感情好族檬,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著化戳,像睡著了一般单料。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天看尼,我揣著相機(jī)與錄音递鹉,去河邊找鬼。 笑死藏斩,一個(gè)胖子當(dāng)著我的面吹牛躏结,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播狰域,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼媳拴,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了兆览?” 一聲冷哼從身側(cè)響起屈溉,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎抬探,沒想到半個(gè)月后子巾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡小压,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年线梗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片怠益。...
    茶點(diǎn)故事閱讀 38,617評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡仪搔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蜻牢,到底是詐尸還是另有隱情烤咧,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布抢呆,位于F島的核電站煮嫌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏抱虐。R本人自食惡果不足惜昌阿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望梯码。 院中可真熱鬧宝泵,春花似錦、人聲如沸轩娶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鳄抒。三九已至闯捎,卻和暖如春椰弊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瓤鼻。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工秉版, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人茬祷。 一個(gè)月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓清焕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親祭犯。 傳聞我的和親對象是個(gè)殘疾皇子秸妥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容