Spring原始碼淺析之bean例項的建立過程(一)

狐言不胡言發表於2021-08-20

在之前的文章內容中,簡單介紹了bean定義的載入過程,下面這篇的主要內容就是bean例項的建立過程。

bean例項的建立方式

ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
context.getBean("beanDemo");

首先看到上面的程式碼,使用了getBean方法,那麼建立bean的入口是不是在getBean裡面呢?

通過之前的內容,可以知道,單例bean可以提前例項化,因為能夠提高使用時的效率。原型bean,即多例bean則是在getBean的時候進行例項化的。而且單例bean和原型bean的例項化過程是沒有區別的,都是通過getBean方法,在啟動時提前例項化也是使用的getBean方法。

bean例項建立以及配置的方式如下:
image.png

  • 構造方法的方式

通過建構函式建立例項有兩種方式,一種是無參建構函式,一種是有參建構函式

下面是無參建構函式的配置方式:

public class ConstructorBean {

    public ConstructorBean() {
        System.out.println("無參建構函式......");
    }
}
<bean id="constructorBean" class="edu.demo.spring.instantiate.ConstructorBean" />

下面是有參建構函式的配置方式:

public class ConstructorBean {

    public ConstructorBean(String name, int age) {
        System.out.println("帶參建構函式......");
        System.out.println(name + "_" + age);
    }
}
<bean id="constructorBean" class="edu.demo.spring.instantiate.ConstructorBean">
   <constructor-arg index="0" value="翠花" />
   <constructor-arg index="1" value="18" />
</bean>

輸出結果如下:

image.png

  • 靜態工廠方法
public class InstantiateFactory {

    public static String getStaticFactoryMethod() {
       return "靜態工廠方法建立bean......";
    }
}
<bean id="boyService" class="edu.demo.spring.instantiate.InstantiateFactory"
      factory-method="getStaticFactoryMethod" >
     <!--<property name="" ref=""></property>-->
</bean>
  • 非靜態工廠方法
public class InstantiateFactory {

   public String getMemberFactoryMethod(String name) {
      return "非靜態工廠方法建立bean......";
   }
}
<bean id="instantiateFactory" class="edu.demo.spring.instantiate.InstantiateFactory" />

<bean id="grilService" factory-bean="instantiateFactory"
   factory-method="getMemberFactoryMethod" >
   <!--<constructor-arg index="0" value="你好" />-->
</bean>
  • 指定工廠方法

需要繼承FactoryBean介面:

public class BoyFactoryBean implements FactoryBean<Boy> {

   @Override
   public Boy getObject() throws Exception {
      return new Lad("niulang");
   }

   @Override
   public Class<?> getObjectType() {
      return Boy.class;
   }
}
<bean name="boyService2" class="edu.demo.spring.instantiate.BoyFactoryBean">
</bean>

如果要獲取BoyFactoryBean自身,需要加上"&"字首,否則返回的是getObject中的bean,這是由FactoryBean建立的bean例項

Object lsfb2 = context.getBean("boyService2");
System.out.println(lsfb2);
Object lsfb4 = context.getBean("&boyService2");
System.out.println(lsfb4);
BoyFactoryBean lsfb = (BoyFactoryBean) context.getBean("&boyService2");
System.out.println(lsfb);
System.out.println(lsfb.getObject());

分別輸出如下:

image.png

例項化bean的流程

從AbstractApplicationContext類中的refresh()方法看起,這裡有個步驟,是提前例項化一些單例bean:

//完成bean工廠的初始化,初始化所有非懶載入的單例bean
finishBeanFactoryInitialization(beanFactory);

點進去檢視具體的實現:

/**
 * Finish the initialization of this context's bean factory,
 * initializing all remaining singleton beans.
 */
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
   // Initialize conversion service for this context.
   //例項化型別轉換服務
   if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
         beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
      beanFactory.setConversionService(
            beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
   }

   // Register a default embedded value resolver if no bean post-processor
   // (such as a PropertyPlaceholderConfigurer bean) registered any before:
   // at this point, primarily for resolution in annotation attribute values.
   //確保beanFacotory持有嵌入值的解析器
   if (!beanFactory.hasEmbeddedValueResolver()) {
      beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
   }

   // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
   // 提前例項化LoadTimeWeaverAware beans
   String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
   for (String weaverAwareName : weaverAwareNames) {
      getBean(weaverAwareName);
   }

   // Stop using the temporary ClassLoader for type matching.
   beanFactory.setTempClassLoader(null);

   // Allow for caching all bean definition metadata, not expecting further changes.
   // 凍結配置,要進行例項化了,bean定義資訊就不能進行更改了
   beanFactory.freezeConfiguration();

   // Instantiate all remaining (non-lazy-init) singletons.
   // 例項化單例bean
   beanFactory.preInstantiateSingletons();
}

然後會進入preInstantiateSingletons方法:

    /** 按照註冊順序存放的bean定義名稱集合 */
    private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
  // Iterate over a copy to allow for init methods which in turn register new bean definitions.
   // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
   //獲取到所有的bean定義名稱
   List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

根據上面的程式碼可以看到,這個方法剛一進來,就獲取所有的bean定義名稱,這個bean定義的list使用了volatile關鍵字進行修飾,關於volatile不清楚的可以看下之前執行緒方面的文章。

// Trigger initialization of all non-lazy singleton beans...
//觸發所有非懶載入單例bean的初始化
for (String beanName : beanNames) {
   //獲取合併之後的bean定義資訊
   RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
   //如果bean定義不是抽象的,並且是單例的,不是懶載入的,就繼續執行
   if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
      //如果是工廠bean就繼續執行,否則直接執行getBean方法
      if (isFactoryBean(beanName)) {
         //獲取bean,這裡的bean是一個工廠bean
         Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
         if (bean instanceof FactoryBean) {
            FactoryBean<?> factory = (FactoryBean<?>) bean;
            //判斷是不是急需例項化的
            boolean isEagerInit;
            if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
               isEagerInit = AccessController.doPrivileged(
                     (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
                     getAccessControlContext());
            }
            else {
               isEagerInit = (factory instanceof SmartFactoryBean &&
                     ((SmartFactoryBean<?>) factory).isEagerInit());
            }
            //如果這個bean急需例項化,就呼叫getBean方法
            if (isEagerInit) {
               getBean(beanName);
            }
         }
      }
      else {
         //獲取普通bean
         getBean(beanName);
      }
   }
}

FactoryBean是什麼,上面已經有了簡單的使用,FactoryBean雖然也是一個bean,但是它是一個可以生產bean的bean。如果直接使用getBean獲取的是它生產的bean,所以需要使用getBean(& + beanName)才能獲取這個工廠bean。

doGetBean方法介紹

protected <T> T doGetBean(
      String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
      throws BeansException {}

這裡傳過來了四個引數,第一個引數name就是bean定義的名稱,requiredType是bean所需要的型別,args是顯式傳過來的引數,typeCheckOnly是否型別檢查。

args指的就是下面程式碼中的引數:

ConstructorBean constructorBean = (ConstructorBean) context.getBean("constructorBean", new Object[]{1,2,3});

使用剛剛上面的示例,然後debug到doGetBean方法可以看到:

image.png

進入方法的第一步就執行了transformedBeanName方法:

String beanName = transformedBeanName(name);
Object bean;

這個transformedBeanName方法就是獲取到標準的bean定義名稱,什麼是標準的bean定義名稱呢?因為在配置bean定義的時候,可以給這個bean定義一些別名。

當使用getBean("別名")也是可以獲取到這個bean定義的。主要的原因就是底層使用了aliasMap,這個aliasMap的key值就是別名,value值就是真正的bean定義名稱。

/** Map from alias to canonical name. */
private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);
/**
 * Return the bean name, stripping out the factory dereference prefix if necessary,
 * and resolving aliases to canonical names.
 * @param name the user-specified name
 * @return the transformed bean name
 */
protected String transformedBeanName(String name) {
   return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}

這裡又呼叫了BeanFactoryUtils.transformedBeanName和canonicalName兩個方法:

/**
 * 返回bean名稱,必要時去掉工廠解引用字首
 * @param name the name of the bean
 * @return the transformed name
 * @see BeanFactory#FACTORY_BEAN_PREFIX
 */
public static String transformedBeanName(String name) {
   Assert.notNull(name, "'name' must not be null");
   //如果bean名稱不包含&字首,就直接返回
   if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
      return name;
   }
   //去除bean名稱的解引用字首,也就是&字首
   return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
      do {
         beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
      }
      while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
      return beanName;
   });
}
/**
 * 這個方法的作用,就是獲取到真正的bean名稱
 * @param name the user-specified name
 * @return the transformed name
 */
public String canonicalName(String name) {
   String canonicalName = name;
   // Handle aliasing...
   String resolvedName;
   do {
      resolvedName = this.aliasMap.get(canonicalName);
      if (resolvedName != null) {
         canonicalName = resolvedName;
      }
   }
   while (resolvedName != null);
   return canonicalName;
}

canonicalName裡面使用了do...while迴圈來獲取真正的bean名稱,下面來個小例子看一下:

<bean id="constructorBean" name="bean1,bean2,bean3,bean4" class="edu.demo.spring.instantiate.ConstructorBean">
   <constructor-arg index="0" value="翠花" />
   <constructor-arg index="1" value="18" />
</bean>

<alias name="bean2" alias="a"/>
ConstructorBean constructorBean = (ConstructorBean) context.getBean("a");

上面給constructorBean配置了4個別名bean1,bean2,bean3,bean4,而且給別名bean2又配置了一個別名a,也就是別名的別名。

debug後可以看到,這裡傳過來的就是別名bean2的別名a:

image.png
下面的圖中,展示了bean定義別名的aliasMap:
image.png
現在清楚這裡為啥使用do...while迴圈來獲取標準的bean名稱了嗎,就是因為bean定義的別名,也可以有別名。當resolvedName為空,也就是說沒有別名了,就會跳出迴圈,獲取到真正的bean名稱了。

接下來使用if...else分成了兩個部分,先來看下第一部分:

// Eagerly check singleton cache for manually registered singletons.
//從快取中獲取已經例項化的單例bean
Object sharedInstance = getSingleton(beanName);
//如果bean例項存在且顯式傳過來的引數是空的就執行下面的程式碼
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 + "'");
      }
   }
   //這裡,是判斷這個bean是不是FactoryBean,如果是FactoryBean,那麼就要從FactoryBean中建立一個例項
   bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}

下面先看下getSingleton這個方法:

/** 單例bean的快取 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** 單例工廠的快取 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

/** 預載入的單例bean的快取 */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   //首先從單例bean的快取中獲取bean例項
   Object singletonObject = this.singletonObjects.get(beanName);
   //如果沒有獲取到並且這個bean正在建立中就執行下面的內容
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      //加鎖
      synchronized (this.singletonObjects) {
         //從預載入的單例bean的快取中獲取bean例項
         singletonObject = this.earlySingletonObjects.get(beanName);、
         //如果還是沒有獲取到,而且是需要建立早期的引用的
         if (singletonObject == null && allowEarlyReference) {
            //從beanName中獲取單例工廠
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            //如果工廠不為空
            if (singletonFactory != null) {
               //獲取bean
               singletonObject = singletonFactory.getObject();
               //放入預載入的單例bean的快取中
               this.earlySingletonObjects.put(beanName, singletonObject);
               //把bean從singletonFactories中移除,
               //因為已經在上面加入到earlySingletonObjects了,所以singletonFactories就不需要了
               this.singletonFactories.remove(beanName);
            }
         }
      }
   }
   return singletonObject;
}

如果上面的方式沒有獲取到bean例項,那麼就走下面的else方法:

// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
   throw new BeanCurrentlyInCreationException(beanName);
}

首先這裡,是判斷原型bean是否已經在構建中了,來檢測迴圈依賴的,比如建立bean1的時候需要依賴bean2,而建立bean2的過程中又依賴bean1,那麼這樣就會丟擲異常。

下面的程式碼,就是判斷父工廠的:

// Check if bean definition exists in this factory.
//首先,獲取父工廠
BeanFactory parentBeanFactory = getParentBeanFactory();
//如果父工廠不為空,並且本地又不包含這個bean定義,那就從父工廠中獲取
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
   // Not found -> check parent.
   //這一步就是還原原來的bean名稱,因為有factoryBean的存在,
   //上面把它的字首去掉,這裡要加回來
   String nameToLookup = originalBeanName(name);
   //下面就是通過父類去建立bean例項
   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);
   }
}

從上面的程式碼可以看到,parentBeanFactory.getBean,這裡又使用了getBean方法,可見也是遞迴呼叫。

if (!typeCheckOnly) {
   markBeanAsCreated(beanName);
}

上面的程式碼,是判斷,如果這裡不僅僅是做型別檢查,那這裡就記錄一下,記錄該bean已經被建立了。下面是markBeanAsCreated方法:

/** Map from bean name to merged RootBeanDefinition. */
private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);

/** Names of beans that have already been created at least once. */
private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));

protected void markBeanAsCreated(String beanName) {
   //首先,判斷已經建立的bean集合中是否包含該bean
   if (!this.alreadyCreated.contains(beanName)) {
      //加鎖
      synchronized (this.mergedBeanDefinitions) {
         //再次判斷,雙重檢鎖
         if (!this.alreadyCreated.contains(beanName)) {
            // Let the bean definition get re-merged now that we're actually creating
            // the bean... just in case some of its metadata changed in the meantime.
            //這裡,是把合併的bean定義清除掉,讓bean定義重新合併,
            //為了防止這個bean定義發生了變化
            clearMergedBeanDefinition(beanName);
            //把beanName加入到已經建立的集合中
            this.alreadyCreated.add(beanName);
         }
      }
   }
}

然後再次進入下面的程式碼:

RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);

// Guarantee initialization of beans that the current bean depends on.
//獲取依賴的bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
   //迴圈遍歷依賴的bean
   for (String dep : dependsOn) {
      //判斷是不是迴圈依賴,是的話就丟擲異常
      if (isDependent(beanName, dep)) {
         throw new BeanCreationException(mbd.getResourceDescription(), beanName,
               "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
      }
      //註冊依賴的bean
      registerDependentBean(dep, beanName);
      try {
         //獲取到依賴的bean
         getBean(dep);
      }
      catch (NoSuchBeanDefinitionException ex) {
         throw new BeanCreationException(mbd.getResourceDescription(), beanName,
               "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
      }
   }
}

這裡先是獲取合併後的bean定義,然後檢測該bean是否是抽象的,如果是的話,就會丟擲異常,這個判斷在checkMergedBeanDefinition方法內。

然後是看這個bean是否依賴了其他bean,如果有依賴,就把依賴的bean註冊到一個依賴的map中,然後呼叫getBean方法,先把依賴的bean例項化。

最後,如果上面都判斷結束,還是沒有獲取到bean例項的話,就執行下面的程式碼來建立bean例項:

// Create bean instance.
// Scope的處理:單例、原型、其他
//判斷是否單例
if (mbd.isSingleton()) {
   //獲取單例bean,如果獲取不到就進行建立,然後快取到單例bean的集合中
   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的處理
   bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//原型bean的處理
else if (mbd.isPrototype()) {
   // It's a prototype -> create a new instance.
   Object prototypeInstance = null;
   try {
      //多例bean的迴圈依賴檢查,並且做記錄
      beforePrototypeCreation(beanName);
      //建立bean
      prototypeInstance = createBean(beanName, mbd, args);
   }
   finally {
     //釋放迴圈依賴檢查的記錄
      afterPrototypeCreation(beanName);
   }
   //進行工廠bean的處理
   bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
//其他範圍bean的處理
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 {
            //建立bean
            return createBean(beanName, mbd, args);
         }
         finally {
            //釋放迴圈依賴檢查的記錄
            afterPrototypeCreation(beanName);
         }
      });
      //進行工廠bean的處理
      bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
   }
   catch (IllegalStateException ex) {
      throw new BeanCreationException(beanName,
            "Scope '" + scopeName + "' is not active for the current thread; consider " +
            "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
            ex);
   }
}

上面的建立,分成了三個部分,分別是單例、多例和其他範圍的bean,大致的處理過程是一樣的,都呼叫了createBean方法進行建立。

getSingleton方法

下面來看下單例bean的getSingleton方法:

/**
 * Return the (raw) singleton object registered under the given name,
 * creating and registering a new one if none registered yet.
 * @param beanName the name of the bean
 * @param singletonFactory the ObjectFactory to lazily create the singleton
 * with, if necessary
 * @return the registered singleton object
 */
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {}

這個方法用來獲取單例bean,而且會呼叫建立bean的方法。

synchronized (this.singletonObjects) {
   Object singletonObject = this.singletonObjects.get(beanName);
}

首先進行了加鎖,然後從singletonObjects中獲取單例bean,singletonObjects上面已經說過,裡面存放了已經例項化的單例bean集合,這裡先從singletonObjects獲取,如果獲取不到,再進行建立。

/** Flag that indicates whether we're currently within destroySingletons. */
private boolean singletonsCurrentlyInDestruction = false;

/** Collection of suppressed Exceptions, available for associating related causes. */
@Nullable
private Set<Exception> suppressedExceptions;
//如果獲取不到該單例bean,那麼就進行建立
if (singletonObject == null) {
    //判斷該單例bean是否正在銷燬,是的話就拋異常
    if (this.singletonsCurrentlyInDestruction) {
       throw new BeanCreationNotAllowedException(beanName,
             "Singleton bean creation not allowed while singletons of this factory are in destruction " +
             "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
    }
    if (logger.isDebugEnabled()) {
       logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
    }
    //單例bean建立之前的處理,也是進行記錄
    beforeSingletonCreation(beanName);
    //是否新建立的單例bean
    boolean newSingleton = false;
    //記錄在建立過程中產生的異常,可能是的,這個我猜的,哈哈
    boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
    if (recordSuppressedExceptions) {
       this.suppressedExceptions = new LinkedHashSet<>();
    }
}

然後看下beforeSingletonCreation這個方法

/** Names of beans that are currently in creation. */
private final Set<String> singletonsCurrentlyInCreation =
      Collections.newSetFromMap(new ConcurrentHashMap<>(16));

/** Names of beans currently excluded from in creation checks. */
private final Set<String> inCreationCheckExclusions =
      Collections.newSetFromMap(new ConcurrentHashMap<>(16));

protected void beforeSingletonCreation(String beanName) {
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
      throw new BeanCurrentlyInCreationException(beanName);
   }
}

進行了判斷和新增,inCreationCheckExclusions是排除的bean名稱集合,也就是說這個bean不會被建立。singletonsCurrentlyInCreation記錄當前正在建立的bean名稱。

下面就是進行建立的程式碼:

try {
   //singletonFactory就是執行上面的建立bean程式碼
   singletonObject = singletonFactory.getObject();
   //建立完成後,標誌為新的單例bean
   newSingleton = true;
}

然後下面的程式碼就是進行一些快取:

finally {
   if (recordSuppressedExceptions) {
      this.suppressedExceptions = null;
   }
   //移除記錄
   afterSingletonCreation(beanName);
}
//如果是新的單例bean,就進行一些快取
if (newSingleton) {
   addSingleton(beanName, singletonObject);
}

看下afterSingletonCreation方法,就是把當前的bean從正在建立的集合中移除掉

protected void afterSingletonCreation(String beanName) {
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
      throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
   }
}

然後下面就是快取的方法了:

protected void addSingleton(String beanName, Object singletonObject) {
   synchronized (this.singletonObjects) {
      this.singletonObjects.put(beanName, singletonObject);
      this.singletonFactories.remove(beanName);
      this.earlySingletonObjects.remove(beanName);
      this.registeredSingletons.add(beanName);
   }
}

這個方法就比較簡單了,把已經例項化的單例bean加入到singletonObjects集合,因為已經例項化了,所以從singletonFactories和earlySingletonObjects中移除了,而且還加入到了registeredSingletons集合中。

原型bean

下面來看下原型bean的處理:

/** Names of beans that are currently in creation. */
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
      new NamedThreadLocal<>("Prototype beans currently in creation");

protected void beforePrototypeCreation(String beanName) {
   Object curVal = this.prototypesCurrentlyInCreation.get();
   if (curVal == null) {
      this.prototypesCurrentlyInCreation.set(beanName);
   }
   else if (curVal instanceof String) {
      Set<String> beanNameSet = new HashSet<>(2);
      beanNameSet.add((String) curVal);
      beanNameSet.add(beanName);
      this.prototypesCurrentlyInCreation.set(beanNameSet);
   }
   else {
      Set<String> beanNameSet = (Set<String>) curVal;
      beanNameSet.add(beanName);
   }
}
protected void afterPrototypeCreation(String beanName) {
   Object curVal = this.prototypesCurrentlyInCreation.get();
   if (curVal instanceof String) {
      this.prototypesCurrentlyInCreation.remove();
   }
   else if (curVal instanceof Set) {
      Set<String> beanNameSet = (Set<String>) curVal;
      beanNameSet.remove(beanName);
      if (beanNameSet.isEmpty()) {
         this.prototypesCurrentlyInCreation.remove();
      }
   }
}

從上面的原始碼,可以看到,prototypesCurrentlyInCreation使用到了ThreadLocal,可以避免執行緒重複建立bean,afterPrototypeCreation是把這個標誌給移除掉。而scope和原型bean這塊的處理是一樣的。

getObjectForBeanInstance方法

最後呢,還有一個方法沒有看,下面就來看下getObjectForBeanInstance這個方法吧。

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

這裡傳來了四個引數,beanInstance是bean例項,name是原始的bean名稱,也就是可能包含&字首,beanName是標準的bean名稱,mbd是合併之後的bean定義資訊。

/** Package-visible field for caching if the bean is a factory bean. */
@Nullable
volatile Boolean isFactoryBean;
//判斷是不是工廠bean
if (BeanFactoryUtils.isFactoryDereference(name)) {
   //如果是NullBean,直接返回
   if (beanInstance instanceof NullBean) {
      return beanInstance;
   }
   //如果不是FactoryBean型別,直接丟擲異常
   //是工廠bean,但是不是FactoryBean型別
   if (!(beanInstance instanceof FactoryBean)) {
      throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
   }
   //設定isFactoryBean標誌,標誌該bean是工廠bean
   if (mbd != null) {
      mbd.isFactoryBean = true;
   }
   //返回bean例項
   return beanInstance;
}

判斷是不是工廠bean的方法,比較簡單,判斷是不是以&開頭的:

public static boolean isFactoryDereference(@Nullable String name) {
   return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
}

如果當前bean例項不是FactoryBean型別,直接返回

// 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.
if (!(beanInstance instanceof FactoryBean)) {
   return beanInstance;
}

如果上面都沒有獲取到bean例項,則執行下面的程式碼:

/** Cache of singleton objects created by FactoryBeans: FactoryBean name to object. */
private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);

Object object = null;
if (mbd != null) {
   mbd.isFactoryBean = true;
}
else {
   //從快取中獲取bean
   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.
   //如果bean定義為空,且beanDefinitionMap中包含該bean名稱,則獲取合併後的bean定義
   if (mbd == null && containsBeanDefinition(beanName)) {
      mbd = getMergedLocalBeanDefinition(beanName);
   }
   //是否是使用者自定義的bean
   boolean synthetic = (mbd != null && mbd.isSynthetic());
   //從FactoryBean中獲取bean
   object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;

getCachedObjectForFactoryBean方法比較簡單,直接從快取的map中獲取即可:

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

再然後就是getObjectFromFactoryBean,從FactoryBean中來獲取物件:

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess)

這裡傳過來三個引數,factory就是上面傳過來的factoryBean,beanName就是配置裡面定義的bean名稱,shouldPostProcess的意思是:是否允許bean進行後置處理。

if (factory.isSingleton() && containsSingleton(beanName)) {
  synchronized (getSingletonMutex()) {
   }
}

首先上來就是判斷,這個factory是不是單例的,單例bean的集合中是否包含這個bean名稱,如果都滿足就執行下面的程式碼。

/** 由FactoryBean建立的單例物件的快取:物件的FactoryBean名稱 */
private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);
//首先從快取中獲取
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)
   //再次從快取中獲取,由於迴圈引用可能導致這個bean已經在快取中了
   Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
   //獲取到了就直接賦值
   if (alreadyThere != null) {
      object = alreadyThere;
   }
   else {
      if (shouldPostProcess) {
          //當前bean正在建立直接返回,暫時不做後置處理
         if (isSingletonCurrentlyInCreation(beanName)) {
            // Temporarily return non-post-processed object, not storing it yet..
            return object;
         }
         //迴圈依賴檢查,做記錄
         beforeSingletonCreation(beanName);
         try {
            //對這個bean做後置處理
            object = postProcessObjectFromFactoryBean(object, beanName);
         }
         catch (Throwable ex) {
            throw new BeanCreationException(beanName,
                  "Post-processing of FactoryBean's singleton object failed", ex);
         }
         finally {
            //迴圈依賴檢查,移除
            afterSingletonCreation(beanName);
         }
      }
      //當前bean是否在單例bean的集合中,如果是的就快取
      if (containsSingleton(beanName)) {
         this.factoryBeanObjectCache.put(beanName, object);
      }
   }
}
//返回bean例項
return object;

再然後就是else裡面的處理,程式碼量較少,if裡面已經有相同的程式碼了。

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;

doGetObjectFromFactoryBean方法:

private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, 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 {
         //這裡,直接呼叫了getObject方法
         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中獲取到getObject裡面的bean例項。

建立例項流程圖

下面,根據上面的原始碼內容,做一個簡單的流程圖,方便進行總結和檢視:

image.png

到此,getBean相關的內容已經介紹完畢了,下面就是真正建立bean例項的過程了。文章旨在記錄學習內容和分享,如有不足還請見諒,文章中若有錯誤的地方,還望大佬不吝賜教,及時指正,共同學習,共同進步,互勉!

相關文章