FactoryBean

友情提示:如果時間緊,任務重,可以直接查看頁面最後的總結。

 

一提到FactoryBean,大家可能會立馬想到BeanFactory,這兩個單詞已經被我混淆了不知多少次,總是記不住誰是誰的誰,這裡其實就記住他們的最後一個單詞去區分他們就好了(Bean、Factory),那麼為了讓大家對這兩個概念有更清楚的了解,我們就來說一下他們兩個之間的區別

從他們的尾部單詞可知,FactoryBean是一個Bean,而BeanFactory是我們所說的容器,具有管理Bean的功能,前面我們已經講述過BeanFactory相關的功能,這裡我們不在過多的贅述,他倆的直觀區別就是一個是bean,一個是管理bean的容器

FactoryBean是一種特殊的Bean,FactoryBean介面定義了三個方法

public interface FactoryBean<T> {
​
   String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
   
   @Nullable
    //返回有FactoryBean創建的Bean實例,如果isSingleton()返回true,則該實例會放到Spring容器的單實例快取池中。 
   T getObject() throws Exception;
   
   @Nullable
    //返回FactoryBean創建Bean的類型。 
   Class<?> getObjectType();
​
    //確定由FactoryBean創建Bean的作用域是singleton還是prototype. 
   default boolean isSingleton() {
      return true;
   }
}

 

一般,我們都會通過實現Spring內部中的FactoryBean介面去創建一個自定義的factorybean

@Component
public class FactoryBeanTest implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return new ObjectBean();
    }
​
    @Override
    public Class<?> getObjectType() {
        return ObjectBean.class;
    }
}
package com.beans;
​
public class ObjectBean {
}
 

然後再在配置類中去獲取在getObject()方法中生成的ObjectBean對象

@ComponentScan("com.beans")
public class mainT {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(mainT.class);
        System.out.println(context.getBean("factoryBeanTest"));
        System.out.println(context.getBean("factoryBeanTest"));
        System.out.println(context.getBean("factoryBeanTest"));
        //System.out.println(context.getBean("&factoryBeanTest"));
        }
}

 

在這裡提出一個疑問:上述獲得的三個Bean是否是同一個?

答案 : 是同一個 ,因為FactoryBean中有一個默認的方法,是否是單例,默認為true,如果想得到非單例,可以重寫這個默認方法

default boolean isSingleton() {
      return true;
   }

 

即默認是單例的。

在提出一個疑問?上述4個Bean得到的是否是同一個類

答案:不是

System.out.println(context.getBean("factoryBeanTest"));
System.out.println(context.getBean("factoryBeanTest"));
System.out.println(context.getBean("factoryBeanTest"));
//com.beans.ObjectBean@77f80c04
//com.beans.ObjectBean@77f80c04
//com.beans.ObjectBean@77f80c04
System.out.println(context.getBean("&factoryBeanTest"));
//com.beans.FactoryBeanTest@1dac5ef

 

上面的注釋是每一個輸出語句輸出的結果,可以發現上方三個beanName沒有加&號的得到的bean是在FactoryBean中getObject方法new的類,而加了&符號的得到的是FactoryBean自身。

所以當你需要得到FactoryBean自身的話,在getBean的時候要在BeanName前加上一個或多個&即可。

那麼Spring如何去處理這個名字呢,我們可以看一下Spring中的源碼

//返回BeanName,去掉FatoryBean的&前綴,並且把name當作別名去aliasMap中尋找原始的beanName
protected String transformedBeanName(String name) {
    return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
public static String transformedBeanName(String name) {
    Assert.notNull(name, "'name' must not be null");
    if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
        return name;
    }
    //如果BeanName以&開頭,截取&後的beanname,並且把截取前後的name存儲到transformedBeanNameCache中
    return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
        do {
            beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
        }
        while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
        return beanName;
    });
}

 

 
public String canonicalName(String name) {
    String canonicalName = name;
    // Handle aliasing...
    String resolvedName;
    do {
        //去找原始beanName,aliasMap:{別名:原始名}
        resolvedName = this.aliasMap.get(canonicalName);
        if (resolvedName != null) {
            canonicalName = resolvedName;
        }
    }
    while (resolvedName != null);
    //如果通過別名找到原始beanName,則返回找出的原始beanName,如果沒有找到,則返回傳進來的BeanName
    return canonicalName;
}

 

上述就是Spring處理這個beanName的方法,如果對上面程式碼有疑問或者不接,可以看作者做得一個流程圖,來幫助您加深記憶,更容易理解

 

這裡要說一下,Spring在getbean之前也就是在啟動的時候就會把FactoryBeanTest都載入到的BeanFactory中的單例池中,但沒有載入ObjectBean。

那麼除了FactoryBean以外還可以通過什麼來new一個對象而得到一個bean呢

就是@Bean註解,如下面例子所示:

@Configuration
public class mainConfiguration {
​
    @Bean
    public ObjectBean getObjectBean(){
        return new ObjectBean();
    }
​
}

 

那麼可以通過@Bean註解以一個相同的方法來得到一個Bean,為什麼還需要FactoryBean來定義一個Bean呢?因為當一個類繼承了FactoryBean之後,它還可以繼承其他的類和介面,起到一個拓展的作用。

public class FactoryBeanTest implements FactoryBean, BeanFactoryPostProcessor...

 

那麼在getBean方法中是如何去判斷這個Bean是不是一個FactoryBean以及如何載入getObject()方法中取到得對象為bean得呢

我們一同來看一下getBean()方法的源碼,只需要看前半部分即可

protected <T> T doGetBean(
            String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
            throws BeansException {
        //返回BeanName,去掉FatoryBean的&前綴,並且把name當作別名去aliasMap中尋找原始的beanName
        String beanName = transformedBeanName(name);
        Object beanInstance;
​
        // 根據beanName從單例池中獲取bean
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            if (logger.isTraceEnabled()) {
                if (isSingletonCurrentlyInCreation(beanName)) {
                    logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                            "' that is not fully initialized yet - a consequence of a circular reference");
                }
                else {
                    logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }
            //判斷sharedInstance是不是FactoryBean
            beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }
​
//      else {
//          // Fail if we're already creating this bean instance:
//          // We're assumably within a circular reference.
//          if (isPrototypeCurrentlyInCreation(beanName)) {
//              throw new BeanCurrentlyInCreationException(beanName);
//          }
//
//          // Check if bean definition exists in this factory.
//          BeanFactory parentBeanFactory = getParentBeanFactory();
//          if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
//              // Not found -> check parent.
//              String nameToLookup = originalBeanName(name);
//              if (parentBeanFactory instanceof AbstractBeanFactory) {
//                  return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
//                          nameToLookup, requiredType, args, typeCheckOnly);
//              }
//              else if (args != null) {
//                  // Delegation to parent with explicit args.
//                  return (T) parentBeanFactory.getBean(nameToLookup, args);
//              }
//              else if (requiredType != null) {
//                  // No args -> delegate to standard getBean method.
//                  return parentBeanFactory.getBean(nameToLookup, requiredType);
//              }
//              else {
//                  return (T) parentBeanFactory.getBean(nameToLookup);
//              }
//          }
//            //父子容器都沒有才去創建
//          if (!typeCheckOnly) {
//              markBeanAsCreated(beanName);
//          }
//
//          StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
//                  .tag("beanName", name);
//          try {
//              if (requiredType != null) {
//                  beanCreation.tag("beanType", requiredType::toString);
//              }
//              RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//              checkMergedBeanDefinition(mbd, beanName, args);
//
//              // Guarantee initialization of beans that the current bean depends on.
//              String[] dependsOn = mbd.getDependsOn();
//              if (dependsOn != null) {
//                  for (String dep : dependsOn) {
//                      //判斷beanName是不是也被dep依賴了,如果是,就是相互依賴
//                      if (isDependent(beanName, dep)) {
//                          throw new BeanCreationException(mbd.getResourceDescription(), beanName,
//                                  "Circular depends-on relationship between '" + beanName + "' and '" + //dep + "'");
//                      }
//                      //載入依賴的bean
//                      //存在在兩個map中
//                      //1、dependentBeanMap ,key為dep,value是一個LinkedHashSet,表示dep被哪些bean依賴了
//                      //2、dependenciesForBeanMap key為beanName,value是一個LinkedHashSet,表示beanName依賴了哪些bean
//                      registerDependentBean(dep, beanName);
//                      try {
//    //先去生成所依賴的bean
//    getBean(dep);
//    }
//    catch (NoSuchBeanDefinitionException ex) {
//    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
//    "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
//    }
//    }
//    }
//
//    // Create bean instance.
//    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;
//    }
//    });
//    //sharedInstance可能是一個FactoryBean,所以需要單獨再去factoryBeanObjectCache中去獲取對應的對象
//    beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
//    }
//
//    else if (mbd.isPrototype()) {
//    // It's a prototype -> create a new instance.
//    Object prototypeInstance = null;
//    try {
//    beforePrototypeCreation(beanName);
//    prototypeInstance = createBean(beanName, mbd, args);
//    }
//    finally {
//    afterPrototypeCreation(beanName);
//    }
//    beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
//    }
//                //其他的scope request,session
//    else {
//    String scopeName = mbd.getScope();
//    if (!StringUtils.hasLength(scopeName)) {
//    throw new IllegalStateException("No scope name defined for bean ´" + beanName + //"'");
//    }
//    Scope scope = this.scopes.get(scopeName);
//    if (scope == null) {
//    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + //"'");
//    }
//    try {
//    Object scopedInstance = scope.get(beanName, () -> {
//    beforePrototypeCreation(beanName);
//    try {
//    return createBean(beanName, mbd, args);
//    }
//    finally {
//    afterPrototypeCreation(beanName);
//    }
//    });
//    beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
//    }
//    catch (IllegalStateException ex) {
//    throw new ScopeNotActiveException(beanName, scopeName, ex);
//    }
//    }
//    }
//    catch (BeansException ex) {
//    beanCreation.tag("exception", ex.getClass().toString());
//    beanCreation.tag("message", String.valueOf(ex.getMessage()));
//    cleanupAfterBeanCreationFailure(beanName);
//    throw ex;
//    }
//    finally {
//    beanCreation.end();
//    }
//    }
//
//    return adaptBeanInstance(name, beanInstance, requiredType);
//  }

 

/**
* @param beanInstance 從單例池中獲取到的bean
* @param name  原始name(沒有經過任何處理,比如,沒有去掉&符號)
* @param beanName  經過轉換後的name(例如:去掉了&符號)
* @param mbd null
* @return
*/
protected Object getObjectForBeanInstance(
            Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
​
        // Don't let calling code try to dereference the factory if the bean isn't a factory.
        //如果是&FactoryBean,那麼直接返回單例池中的對象,這裡就是判斷原始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;
        }
​
        // 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.
        // 如果從單例池中的拿出來的Bean沒有繼承FactoryBean且beanName沒有以&開頭,則認為是普通bean,直接返回
        if (!(beanInstance instanceof FactoryBean)) {
            return beanInstance;
        }
        // 如果beanInstance是FactoryBean且BeanName是以&開頭的
        Object object = null;
        if (mbd != null) {
            mbd.isFactoryBean = true;
        }
        else {
            //首先去快取中通過BeanName獲取getObject方法得到的bean(這是為單例準備的)
            object = getCachedObjectForFactoryBean(beanName);
        }
        //從factoryBeanObjectCache中沒有拿到則進行創建
        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)) {
                //獲取合併後beanDefinition
                mbd = getMergedLocalBeanDefinition(beanName);
            }
            boolean synthetic = (mbd != null && mbd.isSynthetic());
            //調用getObject方法得到對象並放入factoryBeanObjectCache中
            object = getObjectFromFactoryBean(factory, beanName, !synthetic);
        }
        return object;
    }

 

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) {
                    //調用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 {
                                //調用BeanPostProcessor執行初始化後的邏輯,主要就是進行AOP
                                object = postProcessObjectFromFactoryBean(object, beanName);
                            }
                            catch (Throwable ex) {
                                throw new BeanCreationException(beanName,
                                        "Post-processing of FactoryBean's singleton object failed", ex);
                            }
                            finally {
                                afterSingletonCreation(beanName);
                            }
                        }
                        //如果是單例的,存入factoryBeanObjectCache中 
                        //{工廠bean的名(沒有&符號):getObject()方法中new的新對象}
                        if (containsSingleton(beanName)) {
                            this.factoryBeanObjectCache.put(beanName, object);
                        }
                    }
                }
                return object;
            }
        }
        //當FactoryBean不是單例的情況下
        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;
        }
    }

 

下面是一個流程圖,幫您加深印象以及能夠更好得了解上面得過程

 

總結:

1、什麼是FactoryBean

FactoryBean本質上是一個Bean,但他是一個特殊的Bean,而是一個能夠生產和修飾對象生成的工廠Bean。

2、FactoryBean與BeanFactory的區別

如1所說,FactoryBean本質上是一個Bean,但他比較特殊,它是可以生產和修飾對象生成的工廠Bean。

BeanFactory本質上是一個容器,所有Bean都是由BeanFactory來管理的,BeanFactory是一個介面,提供了IOC容器應遵守的最基本的介面,他的核心實現類是DefaultListableBeanFactory。

3、FactoryBean生產的Bean默認是單例的還是多例的

默認是單例的,可以重寫它的isSingleton()方法,修改返回值為false即可變為多例

4、如何獲得FactoryBean本身這個Bean

可以通過在beanName前加上一個或多個&符號來獲取

例如:getBean(“&FactoryBean的名字”)

 

Tags: