Spring 源碼解析—Bean的加載前奏

Spring源碼解析——Bean的加載前奏

User user = (User)context.getBean("testbean");

由這句入手

AbstractBeanFactory#getBean

@Override
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}

@SuppressWarnings("unchecked")
protected <T> T doGetBean(
        final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
        throws BeansException {
    // 提取對應的 beanName
    final String beanName = transformedBeanName(name);
    Object bean;

    // Eagerly check singleton cache for manually registered singletons.
    /**
    檢查緩存中或者實例工廠中是否有對應的實例
    為什么首先會使用這段代碼呢,因為在創建單例 bean 的時候會存在依賴注入的情況,
    而在創建依賴的時候為了避免循環依賴,Spring 創建 bean 的原則是不等 bean 創建
    完成就會將創建的 bean 的 ObjectFactory 提前曝光,也就是將 ObjectFactory 加入
    緩存中,一旦下個 bean 創建時候需要依賴上個 bean 則直接使用 ObjectFactory
    **/
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        if (logger.isDebugEnabled()) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                        "' that is not fully initialized yet - a consequence of a circular reference");
            }
            else {
                logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
        // 返回對應的實例,有時候存在諸如 BeanFactory 的情況并不是直接返回實例本身而是返回指定方法返回的實例
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

    else {
        // Fail if we're already creating this bean instance:
        // We're assumably within a circular reference.
        /**
        只有在單例情況才會嘗試解決依賴循環,原型模型情況,如果存在
        A 中有 B 的熟悉,B 中有 A 的屬性,那么當依賴注入的時候,就會產生當 A 還未創建完的時候
        因為對于 B 的創建再次返回創建 ,造成依賴循環,也就是下面的情況
        **/
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        // Check if bean definition exists in this factory.
        BeanFactory parentBeanFactory = getParentBeanFactory();
        // 如果 beanDefinitionMap 中也就是在所有已經加載的類中不包括 beanName 則
        // 嘗試從 parentBeanFactory 中檢測
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            // Not found -> check parent.
            String nameToLookup = originalBeanName(name);
            // 遞歸到 BeanFactory 中尋找
            if (args != null) {
                // Delegation to parent with explicit args.
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else {
                // No args -> delegate to standard getBean method.
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
        }

        // 如果不是僅僅做類型檢查則是創建 bean,這里要進行記錄
        if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }

        try {
            // 將存儲 XML 配置文件的 GernericBeanDefinition 轉換為 RootBeanDefinition,
            // 如果指定 BeanName 是子 Bean 的話同時會合并父類的相關屬性
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            // Guarantee initialization of beans that the current bean depends on.
            String[] dependsOn = mbd.getDependsOn();
            // 若存在依賴則需要遞歸實例化依賴的 bean
            if (dependsOn != null) {
                for (String dep : dependsOn) {
                    if (isDependent(beanName, dep)) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
                      // 緩存依賴調用
                    registerDependentBean(dep, beanName);
                    getBean(dep);
                }
            }

            // Create bean instance.
            // 實例化依賴的 bean 后便可以實例化 mbd 本身了
            // singleton 模式的創建
            if (mbd.isSingleton()) {
                sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                    @Override
                    public Object getObject() throws BeansException {
                        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);
            }

            else if (mbd.isPrototype()) {
                // It's a prototype -> create a new instance.
                // prototype 模式的創建 (new)
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    afterPrototypeCreation(beanName);
                }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }

            else {
                // 指定的 scope 上實例化 bean
                String scopeName = mbd.getScope();
                final 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, new ObjectFactory<Object>() {
                        @Override
                        public Object getObject() throws BeansException {
                            beforePrototypeCreation(beanName);
                            try {
                                return createBean(beanName, mbd, args);
                            }
                            finally {
                                afterPrototypeCreation(beanName);
                            }
                        }
                    });
                    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);
                }
            }
        }
        catch (BeansException ex) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }

    // Check if required type matches the type of the actual bean instance.
    // 檢查需要的類型是否符合 bean 的實際類型
    if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
        try {
            return getTypeConverter().convertIfNecessary(bean, requiredType);
        }
        catch (TypeMismatchException ex) {
            if (logger.isDebugEnabled()) {
                logger.debug("Failed to convert bean '" + name + "' to required type '" +
                        ClassUtils.getQualifiedName(requiredType) + "'", ex);
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }
    return (T) bean;
}

大致過程:

  1. 轉換對應 beanName。這里的 beanName 可能是別名,可能是 FactoryBean,所以需要一系列的解析:

    1. 去除 FactoryBean 的修飾符,也就是如果 name="&aa",那么會首先去除 & 使得 name=aa
    2. 取指定 alias 所表示的最終 beanName,例如別名 A 指向名稱為 B 的 bean 則返回 B;若別名 A 指向別名 B,別名 B 又指向名稱為 C 的 bean 則返回 C
  2. 嘗試從緩存中加載單例

    單例在 Spring 的同一個容器內只會被創建一次,后續在獲取 bean,就直接從單例緩存中獲取了。當然這里也只是嘗試加載,首先嘗試從緩存中加載,如果加載不成功則再次嘗試從 singletonFactories 中加載。

    由于存在依賴注入的問題,所以在 Spring 中創建 bean 的原則是不等 bean 創建完成就會將創建的 ObjectFactory 提早曝光加入到緩存中,一旦下一個 bean 創建需要依賴上一個 bean 則直接使用 ObjectFactory。

  3. bean 的實例化

  4. 原型模式的依賴檢查

    只有單例會嘗試解決循環依賴。

  5. 在非 singleton 下檢測 parentBeanFactory,看是否需要進入 parentBeanFactory 中加載(當前 BeanFactory 中無該 bean 且 parentBeanFactory 存在且存在該 bean)

  6. 將存儲 XML 配置文件的 GernericBeanDefinition 轉換為 RootBeanDefinition。方便 Bean 的后續處理。

  7. 尋找依賴

  8. 針對不同的 scope 進行 bean 的創建

  9. 類型轉換(requiredType = true)

FactoryBean 的使用

一般來說,Spring 是通過反射機制利用 bean 的 class 屬性指定實現類來實例化 bean 的。FactoryBean 是為了對付配置 bean 的復雜性的。

public interface FactoryBean<T> {
    T getObject() throws Exception;
    Class<?> getObjectType();
    // 如果返回 true 則 getObject() 時候會將實例放入 Spring 容器中單實例緩存池中
    boolean isSingleton(); 
}

實現了 XxxFactoryBean之后,解析<bean id="xxx" class="xx.xx.XxxFactoryBean" />時候會調用該其實現的 getObject() 方法

緩存中獲取單例 bean

@Override
public Object getSingleton(String beanName) {
    // 設置 true 表示允許早期依賴
    return getSingleton(beanName, true);
}

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 檢查緩存中是否存在實例
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        // 如果為空,則鎖定全局變量并進行處理
        synchronized (this.singletonObjects) {
            // 如果此 bean 正在加載則不處理
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                // 當某些方法需要提前初始化時候會調用 addSingletonFactory 方法
                // 將對應的 ObjectFactory 初始化策略存儲在 singletonFactories
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    // 調用預先設定的 getObject 方法
                    singletonObject = singletonFactory.getObject();
                    // 記錄在緩存中,earlySingletonObjects 和 singletonFactories 互斥
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

首先嘗試從 singletonObjects 中獲取實例,如果獲取不到,則從 earlySingletonObjects 里面獲取,如果還取不到,則嘗試從 singletonFactories 里面獲取 beanName 對應的 ObjectFactory,然后調用這個 ObjectFactory 的 getObject 來創建 bean,并放到 earlySingletonObjects 中,然后從 singletonFactories 中 remove 掉這個 ObjectFactory。

  • singletonObjects: 用于保存 BeanName 和創建 bean 實例之間的關系,beanName -> beanInstance
  • singletonFactories:用于保存 BeanName 和創建 bean 的工廠之間的關系,beanName -> ObjectFactory
  • earlySingletonObjects:也是保存 BeanName 和創建 bean 實例之間的關系,與singletonObjects的不同之處在于,當一個單例bean被放到這里面后,那么當bean還在創建過程中,就可以通過getBean方法獲取到了,其目的是用來檢測循環引用。
  • registeredSingletons:用來保存當前所有已注冊的bean。

從 bean 的實例中獲取對象

無論是從緩存中獲取到的 bean 還是通過不同的 scope 策略加載的 bean 都只是最原始的 bean 狀態,并不一定是我們最終想要的 bean。舉個例子,假如我們需要對工廠 bean 進行處理,那么這里得到的其實是工廠 bean 的初始狀態,但是我們真正需要的是工廠 bean 中定義的 factory-method 方法中返回的 bean ,而getObjectForBeanInstance 方法就是完成這個工作的。

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

    // Don't let calling code try to dereference the factory if the bean isn't a factory.
     // 如果指定的 name 是工廠相關(以 & 為前綴)且 beanInstance 又不是 FactoryBean 類型則驗證不通過
    if (BeanFactoryUtils.isFactoryDereference(name) && !(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.
    // 現在我們有了個 bean 的實例,這個實例可能會是正常的 bean 或者 FactoryBean
    // 如果是 FactoryBean 我們使用它創建實例,但如果用戶想要直接獲取工廠實例而不是工程對應的
    // getObject 方法對應的實例那么傳入的 name 應該包含前綴 &
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
        return beanInstance;
    }

    // 加載 FactoryBean
    Object object = null;
    if (mbd == null) {
        // 嘗試從緩存中加載 bean
        object = getCachedObjectForFactoryBean(beanName);
    }
    if (object == null) {
        // Return bean instance from factory.
        // 到這里已經明確指定 beanInstance 一定是 FactoryBean 類型
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        // Caches object obtained from FactoryBean if it is a singleton.
        // containsBeanDefinition 檢測 beanDefinitionMap 中也就是在所有已經加載的類中
        // 檢測是否定義 beanName
        if (mbd == null && containsBeanDefinition(beanName)) {
            // 將存儲 XML 配置文件的 GernericBeanDefinition 轉換為 RootBeanDefinition,
            // 如果指定 BeanName 是子 Bean 的話同時會合并父類的相關屬性
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        // 是否是用戶定義而不是應用程序本身定義的
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
}
  1. 對 FactoryBean 正確性的驗證
  2. 對非 FactoryBean 不做任何處理
  3. 對 bean 進行轉換
  4. 將從 Factory 中解析 bean 的工作委托給 getObjectFromFactoryBean
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) {
                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 (object != null && shouldPostProcess) {
                        try {
                            object = postProcessObjectFromFactoryBean(object, beanName);
                        }
                        catch (Throwable ex) {
                            throw new BeanCreationException(beanName,
                                    "Post-processing of FactoryBean's singleton object failed", ex);
                        }
                    }
                    this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
                }
            }
            return (object != NULL_OBJECT ? object : null);
        }
    }
    else {
        Object object = doGetObjectFromFactoryBean(factory, beanName);
        if (object != null && shouldPostProcess) {
            try {
                 // 調用 ObjectFactory 的后處理器
                object = postProcessObjectFromFactoryBean(object, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
            }
        }
        return object;
    }
}

這部分代碼只是做了一件事:返回的 bean 如果是單例,那就必須要保證全局唯一,同時,也因為是單例的,所以不被重復創建,可以使用緩存來提高性能,也就是說已經加載過就要記錄下來以便于下次復用,否則的話就直接獲取了。

所以我們最后是在 doGetObjectFromFactoryBean中看到了自己想要的方法

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(new PrivilegedExceptionAction<Object>() {
                    @Override
                    public Object run() throws Exception {
                            return 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 && isSingletonCurrentlyInCreation(beanName)) {
        throw new BeanCurrentlyInCreationException(
                beanName, "FactoryBean which is currently in creation returned null from getObject");
    }
    return object;
}

我們接下來看 doGetObjectFromFactoryBean 獲取對象之后,最后返回對象的過程中操作 postProcessObjectFromFactoryBean 做了哪些工作?

AbstractAutowireCapableBeanFactory#postProcessObjectFromFactoryBean

protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
    return applyBeanPostProcessorsAfterInitialization(object, beanName);
}

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        result = beanProcessor.postProcessAfterInitialization(result, beanName);
        if (result == null) {
            return result;
        }
    }
    return result;
}

對于后處理器,后面來進行介紹。這里我們只需要了解在 Spring 獲取 bean 的規則中有這樣一條:盡可能保證所有 bean 初始化后都會調用注冊的 BeanPostProcesser 的 postProcessAfterInitialization 方法進行處理,在世紀開發過程中可以根據此特性設計自己的邏輯業務。

獲取單例

之前我們講解了從緩存中獲取單例的過程,那么,如果緩存中不存在已經加載的單例bean就需要從頭開始bean的加載過程了,而Spring中使用getSingleton的重載方法實現bean的加載過程。

AbstractBeanFactory#getBean 片段

// 實例化依賴的 bean 后便可以實例化 mbd 本身了
 // singleton 模式的創建 
if (mbd.isSingleton()) {
    sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
        @Override
        public Object getObject() throws BeansException {
            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);
}

DefaultSingletonBeanRegistry#getSingleton

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "'beanName' must not be null");
    // 全局變量需要同步
    synchronized (this.singletonObjects) {
        // 首先檢查對應的 bean 是否已經加載過了,因為 singleton 模式其實就是復用以創建的 bean,
        // 所以這步是必須的
        Object singletonObject = this.singletonObjects.get(beanName); // 1
        // 如果為空才可以進行 singleton 的 bean 的初始化
        if (singletonObject == null) {
            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 + "'"); // 2
            }
            beforeSingletonCreation(beanName); // 3
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<Exception>();
            }
            try {
                // 初始化 bean
                singletonObject = singletonFactory.getObject(); // 4
                newSingleton = true;
            }
            catch (IllegalStateException ex) {
                // Has the singleton object implicitly appeared in the meantime ->
                // if yes, proceed with it since the exception indicates that state.
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    throw ex;
                }
            }
            catch (BeanCreationException ex) {
                if (recordSuppressedExceptions) {
                    for (Exception suppressedException : this.suppressedExceptions) {
                        ex.addRelatedCause(suppressedException);
                    }
                }
                throw ex;
            }
            finally {
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = null;
                }
                afterSingletonCreation(beanName); // 5
            }
            if (newSingleton) {
                // 加入緩存
                addSingleton(beanName, singletonObject); // 6
            }
        }
        return (singletonObject != NULL_OBJECT ? singletonObject : null); // 7
    }
}
  1. 檢查緩存是否已經加載過了

  2. 若沒有加載,則記錄 beanName 的正在加載狀態

  3. 加載單例前記錄加載狀態,通過 this.singletonsCurrentlyInCreation.add(beanName),以便于對循環依賴進行檢測

     protected void beforeSingletonCreation(String beanName) {
         if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
             throw new BeanCurrentlyInCreationException(beanName);
         }
     }
    
  4. 通過調用參數傳入的 ObjectFactory 的個體 Object 方法實例化 bean

  5. 加載單例后的處理方法調用。當 bean 加載結束后需要移除緩存中對該 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");
         }
     }
    
  6. 將結果記錄至緩存并刪除加載 bean 過程中所記錄的各種輔助狀態

     protected void addSingleton(String beanName, Object singletonObject) {
         synchronized (this.singletonObjects) {
             this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
             this.singletonFactories.remove(beanName);
             this.earlySingletonObjects.remove(beanName);
             this.registeredSingletons.add(beanName);
         }
     }
    
  7. 返回處理結果

雖然我們已經從外部了解了加載bean的邏輯架構,但現在我們還并沒有開始對bean加載功能的探索,之前提到過, bean 的加載邏輯其實是在傳入的 ObjectFactory 類型的參數singletonFactory中定義的,我們反推參數的獲取,得到如下代碼:

sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
    @Override
    public Object getObject() throws BeansException {
        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;
        }
    }
});

ObjectFactory 的核心部分其實只是調用了 createBean 的方法,所以,繼續~

準備創建 bean

AbstractAutowireCapableBeanFactory#createBean

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
    if (logger.isDebugEnabled()) {
        logger.debug("Creating instance of bean '" + beanName + "'");
    }
    RootBeanDefinition mbdToUse = mbd;

    // Make sure bean class is actually resolved at this point, and
    // clone the bean definition in case of a dynamically resolved Class
    // which cannot be stored in the shared merged bean definition.
    // 鎖定 class,根據設置的 class 屬性或者根據 className 來解析 Class
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName); // 1
    // 如果解析成功則 clone RootBeanDefinition 并且設置其 bean 類為解析之后的 class
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }

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

    try {
        // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
        // 給 BeanPostProcessors 一個機會來返回代理來替代真正的實例
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse); // 3
        if (bean != null) {
            return bean;
        }
    }
    catch (Throwable ex) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                "BeanPostProcessor before instantiation of bean failed", ex);
    }

    Object beanInstance = doCreateBean(beanName, mbdToUse, args); // 4
    if (logger.isDebugEnabled()) {
        logger.debug("Finished creating instance of bean '" + beanName + "'");
    }
    return beanInstance;
}
  1. 根據設置的 class 屬性或者根據 className 來解析 Class
  2. 對 override 屬性進行標記及驗證(lookup-method and replace-method
  3. 應用初始化前的后處理器,解析指定 bean 是否存在初始化前的短路操作
  4. 創建 bean

處理 override 屬性

public void prepareMethodOverrides() throws BeanDefinitionValidationException {
    // Check that lookup methods exists.
    MethodOverrides methodOverrides = getMethodOverrides();
    if (!methodOverrides.isEmpty()) {
        Set<MethodOverride> overrides = methodOverrides.getOverrides();
        synchronized (overrides) {
            for (MethodOverride mo : overrides) {
                prepareMethodOverride(mo);
            }
        }
    }
}

protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
    // 獲取對應類中對應方法名的個數
    int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
    if (count == 0) {
        throw new BeanDefinitionValidationException(
                "Invalid method override: no method with name '" + mo.getMethodName() +
                "' on class [" + getBeanClassName() + "]");
    }
    else if (count == 1) {
        // Mark override as not overloaded, to avoid the overhead of arg type checking.
        // 標記 MethoOverride 暫未被覆蓋,避免參數類型檢查的開銷
        mo.setOverloaded(false);
    }
}

對于方法的匹配來講,如果一個類中存在若干個重載方法,那么,在函數調用及增強的時候還需要根據參數類型進行匹配,來最終確認當前調用的到底是哪個函數。但是,Spring將一部分匹配工作在這里完成了,如果當前類中的方法只有一個,那么就設置重載該方法沒有被重載,這樣在后續調用的時候便可以直接使用找到的方法,而不需要進行方法的參數匹配驗證了,而且還可以提前對方法存在性進行驗證,正可謂一箭雙雕。

實例化的前置處理

AOP基于前置處理后的短路判斷

try {
    // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
    // 給 BeanPostProcessors 一個機會來返回代理來替代真正的實例
    Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
    // 提供一個短路判斷,當經過處理之后的 bean 若不為空,則直接返回結果。
    // 我們所熟知的 AOP 功能就是基于這里的判斷
    if (bean != null) {
        return bean;
    }
}
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    // 如果尚未被解析
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        // Make sure bean class is actually resolved at this point.
        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;
}

其中 applyBeanPostProcessorsBeforeInstantiationapplyBeanPostProcessorsAfterInitialization 分別對應實例化前后的處理器,實現也挺簡單的,無非是對后處理器中的所有 InstantiationAwareBeanPostProcessor 類型的后處理器進行 postProcessBeforeInstantiation 方法和 BeanPostProcessorpostProcessAfterInitialization 方法的調用

實例化前的后處理器應用

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
            if (result != null) {
                return result;
            }
        }
    }
    return null;
}

實例化后的后處理器應用

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        result = beanProcessor.postProcessAfterInitialization(result, beanName);
        if (result == null) {
            return result;
        }
    }
    return result;
}

在講解從緩存中獲取單例bean的時候就提到過,Spring中的規則是在bean的初始化后盡可能保證將注冊的后處理器的postProcessAfterInitialization方法應用到該bean中,因為如果返回的bean不為空,那么便不會再次經歷普通bean的創建過程,所以只能在這里應用后處理器的postProcessAfterInitialization方法。

循環依賴

什么是循環依賴

循環依賴就是循環引用,就是兩個或多個 bean 相互之間持有對方。循環依賴不是循環調用,循環調用是指方法之間的環調用的,循環調用除非有終止條件,否則無法解決。

Spring 如何解決循環依賴

我們先來定義一個循環引用類:

package io.github.binglau.circle;

/**
 * 文件描述:
 */

public class TestA {
    private TestB testB;

    public void a() {
        testB.b();
    }

    public TestB getTestB() {
        return testB;
    }

    public void setTestB(TestB testB) {
        this.testB = testB;
    }
}


package io.github.binglau.circle;

/**
 * 文件描述:
 */

public class TestB {
    private TestC testC;

    public void b() {
        testC.c();
    }

    public TestC getTestC() {
        return testC;
    }

    public void setTestC(TestC testC) {
        this.testC = testC;
    }
}

package io.github.binglau.circle;

/**
 * 文件描述:
 */

public class TestC {
    private TestA testA;

    public void c() {
        testA.a();
    }

    public TestA getTestA() {
        return testA;
    }

    public void setTestA(TestA testA) {
        this.testA = testA;
    }
}

在 Spring 中將循環依賴的處理分成了 3 中情況

構造器循環依賴

無法解決,拋出 BeanCurrentlyInCreationException 異常

Spring容器將每一個正在創建的bean標識符放在一個“當前創建bean池”中,bean標識符在創建過程中將一直保持在這個池中,因此如果在創建 bean 過程中發現自己已經在“當前創建bean池”里時,將拋出BeanCurrentlyInCreationException異常表示循環依賴;而對于創建完畢的bean將從“當前創建bean池”中清除掉。

直觀的測試

  1. 創建配置文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
    
        <bean id="testA" class="io.github.binglau.circle.TestA">
            <constructor-arg index="0" ref="testB"/>
        </bean>
    
        <bean id="testB" class="io.github.binglau.circle.TestB">
            <constructor-arg index="0" ref="testC"/>
        </bean>
    
        <bean id="testC" class="io.github.binglau.circle.TestC">
            <constructor-arg index="0" ref="testA"/>
        </bean>
    
    </beans>
    
  2. 創建測試用例

        @Test(expected = BeanCurrentlyInCreationException.class)
        public void testCircleByConstructor() throws Throwable {
            try {
                new ClassPathXmlApplicationContext("test.xml");
            } catch (Exception e) {
                Throwable el = e.getCause().getCause().getCause();
                throw el;
            }
        }
    

setter 循環依賴

表示通過 setter 注入方式構成的循環依賴。對于 setter 注入造成的依賴是通過 Spring 容器提前暴露剛完成構造器注入但未完成其他步驟(如 setter 注入)的 bean 來完成的,而且只能解決單例作用域的 bean 循環依賴。通過提前暴露一個單例工廠方法,從而使其他 bean 能引用到該 bean ,如下代碼所示:

addSingletonFactory(beanName, new ObjectFactory() {
  public Object getObject() throws BeansException {
   return getEarlyBeanReference(beanName, mbd, bean);
  }
});

具體步驟如下:

  1. Spring 容器創建單例 testA bean,首先根據無參構造器創建 bean,并暴露一個 ObjectFactory 用于返回一個提前暴露一個創建中的 bean,并將testA標識符放到 『當前創建 bean 池』,然后進行 setter 注入 testB
  2. Spring 容器創建單例testBbean,首先根據無參構造器創建 bean,并暴露一個ObjectFactory用于返回一個提前暴露一個創建中的 bean,并將“testB”標識符放到『當前創建bean池』,然后進行 setter 注入 circle
  3. Spring 容器創建單例testC bean,首先根據無參構造器創建 bean,并暴露一個ObjectFactory用于返回一個提前暴露一個創建中的 bean,并將testC標識符放到『當前創建bean池』,然后進行setter注入testA。進行注入testA時由于提前暴露了ObjectFactory工廠,從而使用它返回提前暴露一個創建中的 bean。
  4. 最后在依賴注入testBtestA,完成 setter 注入。

prototype 范圍的依賴處理

對于 prototype 作用域 bean,Spring 容器無法完成依賴注入,因為 Spring 容器不進行緩存 prototype 作用域的 bean,因此無法提前暴露一個創建中的 bean。

關于創建 bean 詳見下篇文章

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,665評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,627評論 2 380

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,829評論 18 139
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,923評論 6 342
  • 創建 bean 在經歷過 AbstractAutowireCapableBeanFactory#createBea...
    仗劍詩篇閱讀 2,229評論 0 1
  • 財富自由是一個沒有量化的概念,并沒有硬性的標準說必須得達到多少資產,這就給了我恬不知恥的、說自己勉強達到財務自由的...
    塵世知行者閱讀 1,015評論 5 7
  • 11月22日 晴(大風) 今天考試啦,好緊張呀。今天寫的作文的題目是《如果我能再做一回小學生》。是呀,如果我能再做...
    一諾Abby閱讀 199評論 0 3