Spring源碼學習(二)哎呦,按菜譜做菜與AbstractAutowireCapableBeanFactory.createBean流程差不多

  • 2019 年 10 月 6 日
  • 筆記

入口

上一篇說了,AbstractBeanFactory.getBean的主流程 ,今天來說下其中的createBean方法,程式入口如下:

/**.   * 這個類的核心方法,創建一個bean實例, 填充bean實例,執行後處理等   * @see #doCreateBean  詳見doCreateBean   */  @Override  protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)        throws BeanCreationException {  	  //.....  }

根據注釋核心邏輯在doCreateBean 中,下面咱們就聊聊doCreateBean.

doCreateBean 邏輯說明

主流程

類比按菜譜做菜

1. 實例化Bean BeanDefinition->BeanWrapper(如果是單例,先嘗試從快取中清楚並獲取BeanWrapper)

找到菜譜,先嘗試從收藏中獲取

2.處理MergedBeanDefinitionPostProcessors

融合老婆的要求,到菜譜中。例如:少放鹽

3.允許提前暴露ObjectFactory,解決循環引用問題(必須滿足:單例&&允許循環引用&&對應的bean在創建)

提前告訴老婆菜的大概味道,方便美麗的她準備飲料,也可以方便自己提前找出盤子

4.填充屬性

炒菜

5.執行 init-method方法

試吃

6.有其他bean依賴當前完整bean(必須填充完屬性),移除這些bean,有不能移除的拋出異常

發現之前準備的盤子太小了,換個新的。

7.註冊DisposableBean介面或destroy—method

做個好男人,吃完飯記得刷碗

源碼注釋在最後!!

一圖勝千言(時序圖)

補充說明

1.實例化Bean BeanDefinition->BeanWrapper流程

BeanDerfinition已經上篇已經做過介紹(上一篇blog的傳送門),下面說下BeanWrapper。 org.springframework.beans,BeanWrapper的注釋翻譯如下:

BeanWrapper是Spring中底層javaBean的核心介面 通常不直接使用,而是被BeanFactory和DataBinder使用 它提供對標準javabean的分析和操作的功能。 可以獲取,設置屬性值,獲取屬性值的descriptors,用於查詢可讀,可寫的屬性。 支援無限層嵌套屬性。 BeanWrapper默認不支援對屬性的舊值進行編輯,這樣可以避免getter被調用時產生的副作用 設置 extractOldValueForEditor 為true,可以開啟對舊屬性值進行編輯。

知道了BeanWrapper就不難猜出BeanDefinition->BeanWrapper的大致邏輯了

BeanDefinition->BeanWrapper 就是將bean的元數據,轉換為Bean,但是Bean沒有對屬性進行賦值。 -- 溫安適 胡亂總結於20190921

createBeanInstance的源碼:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {     // 確認 bean的class,在這時已被解析了     Class<?> beanClass = resolveBeanClass(mbd, beanName);     if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {        throw new BeanCreationException(mbd.getResourceDescription(), beanName,              "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());     }     Supplier<?> instanceSupplier = mbd.getInstanceSupplier();     if (instanceSupplier != null) {        return obtainFromSupplier(instanceSupplier, beanName);     }       if (mbd.getFactoryMethodName() != null) {        return instantiateUsingFactoryMethod(beanName, mbd, args);     }     // 判斷 是否重新創建同一bean時     boolean resolved = false;     boolean autowireNecessary = false;     if (args == null) {        synchronized (mbd.constructorArgumentLock) {           if (mbd.resolvedConstructorOrFactoryMethod != null) {              resolved = true;              autowireNecessary = mbd.constructorArgumentsResolved;           }        }     }     if (resolved) {        if (autowireNecessary) {           return autowireConstructor(beanName, mbd, null, null);        }        else {           return instantiateBean(beanName, mbd);        }     }     // 自動注入的構造器的,候選者     Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);     if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||           mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {        return autowireConstructor(beanName, mbd, ctors, args);     }     // 獲得首選的構造器,可能是默認構造器     ctors = mbd.getPreferredConstructors();     if (ctors != null) {        return autowireConstructor(beanName, mbd, ctors, null);     }     // 沒有特別處理簡單實用,無參構造器     return instantiateBean(beanName, mbd);  }

我們可以看到,這個createBeanInstance ,有3種處理方式

  • instantiateUsingFactoryMethod 按照工廠方法進行實例化
  • autowireConstructor 構造函數注入, 構造器選擇大致邏輯:
    1. 如果僅有默認構造器,沒有指定參數,BeanDefinition中也沒有構造器參數,使用默認構造方法。
    2. 如果有多個構造函數,對多個構造方法按照public優於private,同可見性的情況下,參數多的優於參數少的進行排序。一般採用寬鬆匹配模式(可以設置為嚴格匹配),優先選擇參數原值類型匹配的,參數轉換後類型匹配的次之,最後是都不匹配的。如果出現匹配度一致性的,選擇第一個匹配的構造器。
  • instantiateBean 實例化bean,使用默認構造方法。

咱們看下instantiateBean 的邏輯

一般按照反射生成實例的方式如下方式:

public static void main(String[] args) throws Exception{        Class<CouponApplicationTests> clazz=CouponApplicationTests.class;        clazz.newInstance();        Constructor constructorToUse = clazz.getDeclaredConstructor();        constructorToUse.newInstance()  }

Spring是如何實現的基本類似。查閱instantiateBean的源碼發現,其核心邏輯委託給InstantiationStrategy的instantiate方法。Spring5.X的默認InstantiationStrategy 是CglibSubclassingInstantiationStrategy,而instantiate的實現並不在CglibSubclassingInstantiationStrategy中而是在,其父類SimpleInstantiationStrategy中。如下:

@Override  public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {     // Don't override the class with CGLIB if no overrides.     // 如果沒有override方法, 即沒有使用CGLIB重寫     if (!bd.hasMethodOverrides()) {        Constructor<?> constructorToUse;        synchronized (bd.constructorArgumentLock) {           constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;           if (constructorToUse == null) {              final Class<?> clazz = bd.getBeanClass();              if (clazz.isInterface()) {                 throw new BeanInstantiationException(clazz, "Specified class is an interface");              }              try {                 if (System.getSecurityManager() != null) {                    constructorToUse = AccessController.doPrivileged(                          (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);                 }                 else {                    constructorToUse = clazz.getDeclaredConstructor();                 }                 bd.resolvedConstructorOrFactoryMethod = constructorToUse;              }              catch (Throwable ex) {                 throw new BeanInstantiationException(clazz, "No default constructor found", ex);              }           }        }  	  //就是執行constructorToUse.newInstance()        return BeanUtils.instantiateClass(constructorToUse);     }     else {        // Must generate CGLIB subclass.        return instantiateWithMethodInjection(bd, beanName, owner);     }  }

如果沒有MethodOverride,其大致邏輯,跟咱們寫的差不多。 但是如果有MethodOverride則不同。 看到這裡的時候我很好奇hasMethodOverrides和instantiateWithMethodInjection,看名稱我猜測是對@Override註解進行處理,但是看了源碼這個MethodOverrides是指replace-method和lookup-method,這個2配置,我沒有使用過,查詢了源碼與網上的blog。簡單說就是在這裡利用Cglib實現方法注入。 對lookup-method和replace-method的說明您可以查閱

2.循環引用是什麼?Spring 如何解決的?

什麼是循環引用,舉個列子:BeanA引用BeanB,BeanB也引用BeanA

@Component  class BeanA{     @Autowired     BeanB beanB;  }  @Component  class BeanB{     @Autowired     BeanA beanA;  }

Spring只能解決單例類型的循環,其解決幫扶就是提前暴露ObjectFactory,將未填充完屬性的bean提前暴露出來。 流程圖如下:

啰嗦幾句

寫blog比看源碼要費勁的多,我總是嘗試使用生活中的例子比喻主流程,再加一點的補充說明。 以做菜比喻Spring源碼,感覺自己源碼學雖然不透徹,但是胃口好多了。

做菜喻源碼 輪廓漸清晰 理解未透徹 肚子叫呱呱 美餐一頓去 下回咱再聊

populateBean下一篇解決 預計10月2號前

源碼注釋

/**   * Actually create the specified bean. Pre-creation processing has already happened   * at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks.   * <p>Differentiates between default bean instantiation, use of a   * factory method, and autowiring a constructor.   * 創建指定的Bean,此時創建前預處理已經執行了(查看postProcessBeforeInstantiation)。   * 區分默認bean實例化,工廠方法,並自動注入構造函數。   * @param beanName the name of the bean   * @param mbd the merged bean definition for the bean   * @param args explicit arguments to use for constructor or factory method invocation   * @return a new instance of the bean   * @throws BeanCreationException if the bean could not be created   * @see #instantiateBean   * @see #instantiateUsingFactoryMethod   * @see #autowireConstructor   */  protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)        throws BeanCreationException {       // Instantiate the bean.     // 1.實例化bean     BeanWrapper instanceWrapper = null;     if (mbd.isSingleton()) {        //Cache of unfinished FactoryBean instances 從FactoryBean name to BeanWrapper.        //移除未完成的bean的快取中的實例        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);     }     if (instanceWrapper == null) {        //創建Bean實例 將BeanDefinition替換成BeanWrapper        instanceWrapper = createBeanInstance(beanName, mbd, args);     }     final Object bean = instanceWrapper.getWrappedInstance();     Class<?> beanType = instanceWrapper.getWrappedClass();     if (beanType != NullBean.class) {        mbd.resolvedTargetType = beanType;     }     // Allow post-processors to modify the merged bean definition.     synchronized (mbd.postProcessingLock) {        //Bean        if (!mbd.postProcessed) {           try {              //@AutoWired註解在這裡,應用              //2.處理MergedBeanDefinitionPostProcessors              applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);           }           catch (Throwable ex) {              throw new BeanCreationException(mbd.getResourceDescription(), beanName,                    "Post-processing of merged bean definition failed", ex);           }           mbd.postProcessed = true;        }     }     // Eagerly cache singletons to be able to resolve circular references     // even when triggered by lifecycle interfaces like BeanFactoryAware.     // 3.允許提前暴露ObjectFactory,解決循環引用問題     //  單例,允許循環引用,對應的bean在創建     boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&           isSingletonCurrentlyInCreation(beanName));     if (earlySingletonExposure) {        if (logger.isTraceEnabled()) {           logger.trace("Eagerly caching bean '" + beanName +                 "' to allow for resolving potential circular references");        }        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));     }       // Initialize the bean instance.     // 實例化bean     Object exposedObject = bean;     try {        //4.填充屬性        populateBean(beanName, mbd, instanceWrapper);        //5.執行 init-method方法        exposedObject = initializeBean(beanName, exposedObject, mbd);     }     catch (Throwable ex) {        if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {           throw (BeanCreationException) ex;        }        else {           throw new BeanCreationException(                 mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);        }     }     //6.有其他bean依賴當前完整bean(填充過屬性),移除這些bean,有不能移除的拋出異常     if (earlySingletonExposure) {        Object earlySingletonReference = getSingleton(beanName, false);        if (earlySingletonReference != null) {           if (exposedObject == bean) {              exposedObject = earlySingletonReference;           }           else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {              //不允許注入未被完全裝載的bean,並且有其他Bean依賴當前這個Bean              String[] dependentBeans = getDependentBeans(beanName);              Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);              for (String dependentBean : dependentBeans) {                 //移除依賴於當前Bean的其他bean                 if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {                    actualDependentBeans.add(dependentBean);                 }              }              if (!actualDependentBeans.isEmpty()) {                 //還有其他bean,依賴於當前Bean,未被移除                 throw new BeanCurrentlyInCreationException(beanName,                       "Bean with name '" + beanName + "' has been injected into other beans [" +                       StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +                       "] in its raw version as part of a circular reference, but has eventually been " +                       "wrapped. This means that said other beans do not use the final version of the " +                       "bean. This is often the result of over-eager type matching - consider using " +                       "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");              }           }        }     }     // Register bean as disposable.     try {        //7.如果實現了 DisposableBean介面或者提供了destroy—method 在這裡註冊        registerDisposableBeanIfNecessary(beanName, bean, mbd);     }     catch (BeanDefinitionValidationException ex) {        throw new BeanCreationException(              mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);     }     return exposedObject;     }

(adsbygoogle = window.adsbygoogle || []).push({});

Tags: