Spring IoC之AbstractBeanFactory(二)

各 scope 的 bean 建立

在 Spring 中存在着不一樣的 scope,默認是 singleton ,還有 prototype、request 等等其餘的 scope ,接下來咱們分析一下它們的建立過程。java

singleton

Spring 的 scope 默認爲 singleton,其初始化的代碼以下: web

if (mbd.isSingleton()) {
    sharedInstance = this.getSingleton(beanName, () -> {
        try {
            return this.createBean(beanName, mbd, args);
        } catch (BeansException var5) {
            this.destroySingleton(beanName);
            throw var5;
        }
    });
    bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
複製代碼

第一部分分析了從緩存中獲取單例模式的 bean,可是若是緩存中不存在呢?則須要從頭開始加載 bean,這個過程由 getSingleton(beanName, singletonFactory) 實現。 spring

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");
    // 全局加鎖
    synchronized(this.singletonObjects) {
        // 從緩存中檢查一遍
        // 由於 singleton 模式其實就是複用已經建立的 bean 因此這步驟必須檢查
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            ....

            // 加載前置處理
            this.beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = this.suppressedExceptions == null;
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet();
            }

            try {
                // 初始化 bean
                // 這個過程實際上是調用 createBean() 方法,調試的時候能夠發現
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            } catch (IllegalStateException var16) {
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    throw var16;
                }
            } catch (BeanCreationException var17) {
                  ....
            } finally {
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = null;
                }

                // 後置處理
                this.afterSingletonCreation(beanName);
            }

            // 加入緩存中
            if (newSingleton) {
                this.addSingleton(beanName, singletonObject);
            }
        }

        return singletonObject;
    }
}
複製代碼

其實這個過程並無真正建立 bean,僅僅只是作了一部分準備和預處理步驟,真正獲取單例 bean 的方法實際上是由 singletonFactory.getObject() 這部分實現,而 singletonFactory 由回調方法產生。那麼這個方法作了哪些準備呢?緩存

  1. 再次檢查緩存是否已經加載過,若是已經加載了則直接返回,不然開始加載過程。app

  2. 調用 beforeSingletonCreation() 記錄加載單例 bean 以前的加載狀態,即前置處理。ide

  3. 調用參數傳遞的 ObjectFactory 的 getObject() 實例化 bean。函數

  4. 調用 afterSingletonCreation() 進行加載單例後的後置處理。post

  5. 將結果記錄並加入值緩存中,同時刪除加載 bean 過程當中所記錄的一些輔助狀態。測試

    這裏咱們看一下 addSingleton()方法this

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);
    }
}
複製代碼

結合循環依賴章節中所講,這一步就是清除二級和三級緩存中的數據,添加到一級緩存中,位於一級緩存中的單例數據能夠屢次被調用。

接着來重點關注 AbstractAutowireCapableBeanFactory 類中實現的 createBean()方法,其定義以下:

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    if (this.logger.isTraceEnabled()) {
        this.logger.trace("Creating instance of bean '" + beanName + "'");
    }

    RootBeanDefinition mbdToUse = mbd;
    // 確保此時的 bean 已經被解析了
    Class<?> resolvedClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        // 若是獲取的class 屬性不爲null,則克隆該 BeanDefinition
        // 主要是由於該動態解析的 class 沒法保存到到共享的 BeanDefinition
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }

    try {
        // 驗證和準備覆蓋方法
        mbdToUse.prepareMethodOverrides();
    } catch (BeanDefinitionValidationException var9) {
        throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", var9);
    }

    Object beanInstance;
    try {
        // 給 BeanPostProcessors 一個機會用來返回一個代理類而不是真正的類實例
        // AOP 的功能就是基於這個地方
        beanInstance = this.resolveBeforeInstantiation(beanName, mbdToUse);
        if (beanInstance != null) {
            return beanInstance;
        }
    } catch (Throwable var10) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", var10);
    }

    try {
        // 執行真正建立 bean 的過程
        beanInstance = this.doCreateBean(beanName, mbdToUse, args);
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Finished creating instance of bean '" + beanName + "'");
        }

        return beanInstance;
    } catch (ImplicitlyAppearedSingletonException | BeanCreationException var7) {
        throw var7;
    } catch (Throwable var8) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", var8);
    }
}
複製代碼

主要過程以下:

  • 解析指定 BeanDefinition 的 class
  • 處理 override 屬性
  • 實例化的前置處理
  • 建立 bean

prepareMethodOverrides()方法涉及到 BeanDefinition,後續會作介紹。

resolveBeforeInstantiation() 的做用是給 BeanPostProcessors 後置處理器返回一個代理對象的機會,其實在調用該方法以前 Spring 一直都沒有建立 bean ,那麼這裏返回一個 bean 的代理類有什麼做用呢?做用體如今後面的 if 判斷:

if (beanInstance != null) {
    return beanInstance;
}
複製代碼

若是代理對象不爲空,則直接返回代理對象,這一步驟有很是重要的做用,Spring 後續實現 AOP 就是基於這個地方判斷的。

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}
複製代碼

這個方法核心就在於 applyBeanPostProcessorsBeforeInstantiation()applyBeanPostProcessorsAfterInitialization() 兩個方法,before 爲實例化前的後處理器應用,after 爲實例化後的後處理器應用。最終仍是由 BeanPostProcessor 接口實現類來完成相應的工做。

接下來就該最核心的建立 bean 的工做,該過程有 doCreateBean() 實現,以下:

    protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        // BeanWrapper是對Bean的包裝,其接口中所定義的功能很簡單包括設置獲取被包裝的對象,獲取被包裝bean的屬性描述器
        BeanWrapper instanceWrapper = null;
        // 單例模型,則從未完成的 FactoryBean 緩存中刪除
        if (mbd.isSingleton()) {
            instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
        }

        // 使用合適的實例化策略來建立新的實例:工廠方法、構造函數自動注入、簡單初始化
        if (instanceWrapper == null) {
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }

        // 包裝的實例對象
        Object bean = instanceWrapper.getWrappedInstance();
        // 包裝的實例對象的類型
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        // 檢測是否有後置處理
        // 若是有後置處理,則容許後置處理修改 BeanDefinition
        synchronized(mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                } catch (Throwable var17) {
                    ....
                }

                mbd.postProcessed = true;
            }
        }

        // 解決單例模式的循環依賴
        // 單例模式 & 運行循環依賴&當前單例 bean 是否正在被建立
        boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
        if (earlySingletonExposure) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
            }

            this.addSingletonFactory(beanName, () -> {
                return this.getEarlyBeanReference(beanName, mbd, bean);
            });
        }

        Object exposedObject = bean;

        try {
            // 對 bean 進行填充,將各個屬性值注入,其中,可能存在依賴於其餘 bean 的屬性
            // 則會遞歸初始依賴 bean
            this.populateBean(beanName, mbd, instanceWrapper);
            // 調用初始化方法
            exposedObject = this.initializeBean(beanName, exposedObject, mbd);
        } catch (Throwable var18) {
            if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
                throw (BeanCreationException)var18;
            }

            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
        }

        /**
         * 循環依賴處理
         */

        if (earlySingletonExposure) {
            // 獲取 earlySingletonReference
            Object earlySingletonReference = this.getSingleton(beanName, false);
            // 只有在存在循環依賴的狀況下,earlySingletonReference 纔不會爲空
            if (earlySingletonReference != null) {
                // 若是 exposedObject 沒有在initializeBean初始化方法中被改變,也就是沒有被加強
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                } else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
                    String[] dependentBeans = this.getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
                    String[] var12 = dependentBeans;
                    int var13 = dependentBeans.length;

                    for(int var14 = 0; var14 < var13; ++var14) {
                        String dependentBean = var12[var14];
                        if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }

                    if (!actualDependentBeans.isEmpty()) {
                        ....
                    }
                }
            }
        }

        try {
            // 註冊 bean
            this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
            return exposedObject;
        } catch (BeanDefinitionValidationException var16) {
           .....
        }
    }
複製代碼

總體的思路:

  1. 若是是單例模式,則清除 factoryBeanInstanceCache 緩存,同時返回 BeanWrapper 實例對象,固然若是存在。
  2. 若是緩存中沒有 BeanWrapper 或者不是單例模式,則調用 createBeanInstance() 實例化 bean,主要是將 BeanDefinition 轉換爲 BeanWrapper
  3. 單例模式的循環依賴處理 ,在以前的文章有詳細分析過,這裏總結一下:
  • createBeanInstance() 實例化 bean,賦零值
  • populateBean() 屬性填充
  • 循環依賴的處理
  • initializeBean() 初始化 bean,包括前置、後置處理器的調用

建立完 bean 實例後,還會執行 getObjectForBeanInstance()方法,這個方法在緩存中獲取單例 bean 一節有介紹到。

原型模式

else if (mbd.isPrototype()) {
    var11 = null;

    Object prototypeInstance;
    try {
        this.beforePrototypeCreation(beanName);
        prototypeInstance = this.createBean(beanName, mbd, args);
    } finally {
        this.afterPrototypeCreation(beanName);
    }

    bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
複製代碼

原型模式的初始化過程很簡單:直接建立一個新的實例就能夠了。過程以下:

  1. 調用 beforeSingletonCreation() 記錄加載原型模式 bean 以前的加載狀態,即前置處理。
  2. 調用 createBean() 建立一個 bean 實例對象。
  3. 調用 afterSingletonCreation() 進行加載原型模式 bean 後的後置處理。
  4. 調用 getObjectForBeanInstance() 從 bean 實例中獲取對象。

原型模式下,執行 createBean()相對來講簡單一些,這裏就很少作介紹了。不過關於循環依賴隊列中存在原型模式的 bean,須要注意一下,這裏咱們仍是拿以前的案例來進行測試,作一下修改。

修改 beans.xml 文件,將其中的一個 bean 定義爲原型模式:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


    <bean id="car" class="com.msdn.bean.AbstractCar"  p:brand="寶馬" p:money-ref="money" />

    <bean id="person" class="com.msdn.bean.Person" p:name="herish" p:car-ref="car" />

    <bean id="money" class="com.msdn.bean.Money" p:classification="工資" p:person-ref="person" scope="prototype"/>
</beans>
複製代碼

新的測試代碼:

@Test
public void cycleRely(){
    ClassPathResource resource = new ClassPathResource("config/beans.xml");
    BeanFactory beanFactory = new XmlBeanFactory(resource);

    Person person = (Person) beanFactory.getBean("person");
    System.out.println(person);

    Money money = (Money) beanFactory.getBean("money");
    Money money2 = (Money) beanFactory.getBean("money");
    System.out.println(money == money2);
    AbstractCar car = (AbstractCar) beanFactory.getBean("car");
    AbstractCar car2 = (AbstractCar) beanFactory.getBean("car");
    System.out.println(car == car2);
}
複製代碼

運行結果爲:

Person{name='herish', 擁有一輛car=AbstractCar{brand='寶馬', money=Money{classification='工資', person=herish}}}
false
true
複製代碼

從結果來看,貌似沒什麼問題,money 對象確實也再也不是單例,循環依賴也處理成功了。接下來咱們作一下修改:

@Test
public void cycleRely(){
ClassPathResource resource = new ClassPathResource("config/beans.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);

//        Person person = (Person) beanFactory.getBean("person");
//        System.out.println(person);

Money money = (Money) beanFactory.getBean("money");
Money money2 = (Money) beanFactory.getBean("money");
System.out.println(money == money2);
AbstractCar car = (AbstractCar) beanFactory.getBean("car");
AbstractCar car2 = (AbstractCar) beanFactory.getBean("car");
System.out.println(car == car2);
}
複製代碼

運行該代碼會報錯:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'money' defined in class path resource [config/beans.xml]: Cannot resolve reference to bean 'personwhile setting bean property 'person'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'person' defined in class path resource [config/beans.xml]: Cannot resolve reference to bean 'carwhile setting bean property 'car'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'car' defined in class path resource [config/beans.xml]: Cannot resolve reference to bean 'moneywhile setting bean property 'money'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'money': Requested bean is currently in creation: Is there an unresolvable circular reference?
複製代碼

調試該代碼能夠發現問題,因爲mbd.isSingleton()(此處mbd爲money對應的bean)爲false,致使沒有將相應的數據加入到三級緩存中,再次調用 getSingleton(beanName, allowEarlyReference)方法返回結果爲 null,致使進行到 isPrototypeCurrentlyInCreation(beanName)方法時拋出異常。

其餘做用域

String scopeName = mbd.getScope();
Scope 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, () -> {
        this.beforePrototypeCreation(beanName);

        Object var4;
        try {
            var4 = this.createBean(beanName, mbd, args);
        } finally {
            this.afterPrototypeCreation(beanName);
        }

        return var4;
    });
    bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
catch (IllegalStateException var23) {
    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", var23);
}
複製代碼

核心流程和原型模式同樣,只不過獲取 bean 實例是由 scope.get() 實現,以下:

public Object get(String name, ObjectFactory<?> objectFactory) {
    // 獲取 scope 緩存
    Map<String, Object> scope = this.threadScope.get();
    Object scopedObject = scope.get(name);
    if (scopedObject == null) {
        scopedObject = objectFactory.getObject();
        // 加入緩存
        scope.put(name, scopedObject);
    }
    return scopedObject;
}
複製代碼

AbstractBeanFactory 類中對於 getBean(name)方法的講解終於結束了,這也是 bean 加載的過程。

相關文章
相關標籤/搜索