spring原始碼閱讀筆記08:bean載入之建立bean

木瓜芒果發表於2020-04-20

  上文從整體視角分析了bean建立的流程,分析了Spring在bean建立之前所做的一些準備工作,並且簡單分析了一下bean建立的過程,接下來就要詳細分析bean建立的各個流程了,這是一個比較複雜的過程,也是Spring獲取bean中最核心的一部分,主要包括如下部分,下面依次進行詳細分析:

  • 構造bean;
  • 屬性注入;
  • 初始化bean;
  • 註冊DisposableBean;

1. 構造bean

  構造bean的邏輯在createBeanInstance()方法中:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
    // 解析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());
    }
    // 如果工廠方法不為空則使用工廠方法初始化策略
    if (mbd.getFactoryMethodName() != null)  {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }

    // Shortcut when re-creating the same 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() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
            mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
        // 建構函式自動注入
        return autowireConstructor(beanName, mbd, ctors, args);
    }

    // 使用預設建構函式構造
    return instantiateBean(beanName, mbd);
}

  這裡面的邏輯還是比較清晰的:

  1. 如果在RootBeanDefinition中存在factoryMethodName屬性,或者說在配置檔案中配置了factory-method,那麼Spring會嘗試使用instantiateUsingFactoryMethod()方法根據RootBeanDefinition中的配置生成bean的例項。

  2. 解析建構函式並進行建構函式的例項化。因為一個bean對應的類中可能會有多個建構函式,而每個建構函式的引數不同,Spring會根據引數及型別去判斷最終會使用哪個建構函式進行例項化。但是,判斷的過程是一個比較消耗效能的步驟,所以採用了快取機制,即如果已經解析過則不需要重複解析而是直接從RootBeanDefinition中的屬性resolvedConstructorOrFactoryMethod快取的值去取,否則需要再次解析,並將解析的結果新增至RootBeanDefinition中的resolvedConstructorOrFactoryMethod中。

  下面再來看一下例項的建立,對於例項的建立Spring中分成了兩種情況,一種是通用的例項化,另一種是帶有引數的例項化。

1.1 帶引數建構函式例項化

  帶有引數的例項化過程相當複雜,因為存在著不確定性,所以在判斷對應引數上做了大量工作,這個工作是委託給ConstructorResolver這個類: 

public BeanWrapper autowireConstructor(
        final String beanName, final RootBeanDefinition mbd, Constructor<?>[] chosenCtors, final Object[] explicitArgs) {

    BeanWrapperImpl bw = new BeanWrapperImpl();
    this.beanFactory.initBeanWrapper(bw);

    Constructor<?> constructorToUse = null;
    ArgumentsHolder argsHolderToUse = null;
    Object[] argsToUse = null;
    // explicitArgs通過getBean方法傳入
    // 如果getBean方法呼叫的時候指定了方法引數那麼直接使用
    if (explicitArgs != null) {
        argsToUse = explicitArgs;
    }
    else {
        // 如果在getBean方法時候沒有指定則嘗試從配置檔案中解析
        Object[] argsToResolve = null;
        // 嘗試從快取中獲取
        synchronized (mbd.constructorArgumentLock) {
            constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
            if (constructorToUse != null && mbd.constructorArgumentsResolved) {
                // 從快取獲取
                argsToUse = mbd.resolvedConstructorArguments;
                if (argsToUse == null) {
                    // 配置的建構函式引數
                    argsToResolve = mbd.preparedConstructorArguments;
                }
            }
        }
        // 如果快取中存在
        if (argsToResolve != null) {
            // 解析引數型別,如給指定方法的建構函式A(int,int),則通過此方法後就會把配置中的("1","1")轉換為(1,1)
            // 快取中的值可能是原始值也可能是最終值
            argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
        }
    }
    // 沒有被快取
    if (constructorToUse == null) {
        // Need to resolve the constructor.
        boolean autowiring = (chosenCtors != null ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
        ConstructorArgumentValues resolvedValues = null;

        int minNrOfArgs;
        if (explicitArgs != null) {
            minNrOfArgs = explicitArgs.length;
        }
        else {
            // 提取配置檔案中配置的建構函式引數
            ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
            // 用於承載解析後的建構函式引數的值
            resolvedValues = new ConstructorArgumentValues();
            // 能解析到的引數個數
            minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
        }

        // Take specified constructors, if any.
        Constructor<?>[] candidates = chosenCtors;
        if (candidates == null) {
            Class<?> beanClass = mbd.getBeanClass();
            try {
                candidates = (mbd.isNonPublicAccessAllowed() ?
                        beanClass.getDeclaredConstructors() : beanClass.getConstructors());
            }
            catch (Throwable ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,"some exception message ^_^", ex);
            }
        }
        // 排序給定的建構函式,public建構函式優先引數數量降序、非public建構函式引數數量降序
        AutowireUtils.sortConstructors(candidates);
        int minTypeDiffWeight = Integer.MAX_VALUE;
        Set<Constructor<?>> ambiguousConstructors = null;
        List<Exception> causes = null;

        for (int i = 0; i < candidates.length; i++) {
            Constructor<?> candidate = candidates[i];
            Class<?>[] paramTypes = candidate.getParameterTypes();

            if (constructorToUse != null && argsToUse.length > paramTypes.length) {
                // 如果已經找到選用的建構函式並且需要的引數個數大於當前的建構函式引數個數則終止,因為已經按照引數個數降序排列
                break;
            }
            if (paramTypes.length < minNrOfArgs) {
                // 引數個數不相等
                continue;
            }

            ArgumentsHolder argsHolder;
            if (resolvedValues != null) {
                // 有引數則根據值構造對應引數型別的引數
                try {
                    String[] paramNames = null;
                    if (constructorPropertiesAnnotationAvailable) {
                        // 註解上獲取引數名稱
                        paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
                    }
                    if (paramNames == null) {
                        // 獲取引數名稱探索器
                        ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                        if (pnd != null) {
                            // 獲取指定建構函式的引數名稱
                            paramNames = pnd.getParameterNames(candidate);
                        }
                    }
                    // 根據名稱和資料型別建立引數持有者
                    argsHolder = createArgumentArray(
                            beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring);
                }
                catch (UnsatisfiedDependencyException ex) {
                    if (this.beanFactory.logger.isTraceEnabled()) {
                        this.beanFactory.logger.trace(
                                "Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
                    }
                    if (i == candidates.length - 1 && constructorToUse == null) {
                        if (causes != null) {
                            for (Exception cause : causes) {
                                this.beanFactory.onSuppressedException(cause);
                            }
                        }
                        throw ex;
                    }
                    else {
                        // Swallow and try next constructor.
                        if (causes == null) {
                            causes = new LinkedList<Exception>();
                        }
                        causes.add(ex);
                        continue;
                    }
                }
            }
            else {
                // Explicit arguments given -> arguments length must match exactly.
                if (paramTypes.length != explicitArgs.length) {
                    continue;
                }
                // 建構函式沒有引數的情況
                argsHolder = new ArgumentsHolder(explicitArgs);
            }
            // 探測是否有不確定性的建構函式存在,例如不同建構函式的引數為父子關係
            int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
                    argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
            // 如果它代表著當前最接近的匹配則選擇作為建構函式
            if (typeDiffWeight < minTypeDiffWeight) {
                constructorToUse = candidate;
                argsHolderToUse = argsHolder;
                argsToUse = argsHolder.arguments;
                minTypeDiffWeight = typeDiffWeight;
                ambiguousConstructors = null;
            }
            else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
                if (ambiguousConstructors == null) {
                    ambiguousConstructors = new LinkedHashSet<Constructor<?>>();
                    ambiguousConstructors.add(constructorToUse);
                }
                ambiguousConstructors.add(candidate);
            }
        }

        if (constructorToUse == null) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,"some exception message ^_^");
        }
        else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,"some exception message ^_^" + ambiguousConstructors);
        }

        if (explicitArgs == null) {
            // 將解析的建構函式加入快取
            argsHolderToUse.storeCache(mbd, constructorToUse);
        }
    }

    try {
        Object beanInstance;

        if (System.getSecurityManager() != null) {
            final Constructor<?> ctorToUse = constructorToUse;
            final Object[] argumentsToUse = argsToUse;
            beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
                public Object run() {
                    return beanFactory.getInstantiationStrategy().instantiate(
                            mbd, beanName, beanFactory, ctorToUse, argumentsToUse);
                }
            }, beanFactory.getAccessControlContext());
        }
        else {
            beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
                    mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
        }
        // 將構建的例項加入BeanWrapper中
        bw.setWrappedInstance(beanInstance);
        return bw;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
    }
}

  邏輯很複雜,程式碼量也很大,能夠堅持讀完都不容易。總結一下整個函式,主要在以下幾個方面:

1. 建構函式引數的確定

  • 根據explicitArgs引數判斷

  如果傳入的引數explicitArgs不為空,那麼可以直接確定引數,因為explicitArgs引數是在呼叫Bean的時候使用者指定的,在BeanFactory類中存在這樣的方法:

Object getBean(String name, Object... args) throws BeansException;

  在獲取bean的時候,使用者不但可以指定bean的名稱還可以指定bean所對應類的建構函式或者工廠方法的方法引數,主要用於靜態工廠方法的呼叫,而這裡是需要給定完全匹配的引數的,所以,便可以判斷,如果傳入引數explicitArgs不為空,則可以確定建構函式引數就是它。

  • 從快取中獲取

  除此之外,確定引數的辦法如果之前已經分析過,也就是說建構函式引數已經記錄在快取中,那麼便可以直接拿來使用。而且,這裡要提到的是,在快取中快取的可能是引數的最終型別也可能是引數的初始型別,例如:建構函式引數要求的是int型別,但是原始的引數值可能是String型別的"1",那麼即使在快取中得到了引數,也需要經過型別轉換器的過濾以確保引數型別與對應的建構函式引數型別完全對應。

  • 從配置檔案獲取

  如果不能根據傳入的引數explicitArgs確定建構函式引數,也無法在快取中得到相關資訊,那麼就只能從頭分析了。

  經過之前的分析,我們知道,Spring中配置檔案的資訊經過轉換之後都會通過BeanDefinition例項承載,也就是引數mbd中包含的,那麼可以通過呼叫mbd.getConstructorArgumentValues()來獲取配置的建構函式資訊。有了配置中的資訊便可以獲取對應的引數值資訊了,獲取引數值的資訊包括直接指定值,如:直接指定建構函式中某個值為原始型別或String型別,或者是一個對其他bean的引用,這一處理是委託給resolveConstructorArguments()方法,它將返回能解析到的引數的個數。

2. 建構函式的確定

  經過了第一步後已經確定了建構函式的引數,接下來的任務就是根據建構函式引數在所有建構函式中鎖定對應的建構函式,而匹配的方法就是根據引數個數匹配,所以在匹配之前需要先對建構函式按照public建構函式優先引數數量降序、非public建構函式引數數量降序。這樣可以在遍歷的情況下迅速判斷排在後面的建構函式引數個數是否符合條件。

  由於在配置檔案中並不是唯一限制使用引數位置索引的方式去建立,同樣還支援指定引數名稱進行設定引數值的情況,如<constructor-arg name="aa">,那麼這種情況就需要首先確定建構函式中的引數名稱。

  獲取引數名稱有兩種方式,一種是通過註解的方式直接獲取,另一種就是使用Spring中提供的工具類ParameterNameDiscoverer來獲取。建構函式、引數名稱、引數型別、引數值都確定後就可以鎖定建構函式以及轉換對應的引數型別了。

3. 根據確定的建構函式轉換對應的引數型別

  主要是使用Spring中提供的型別轉換器或者使用者提供的自定義型別轉換器進行轉換。

4. 建構函式不確定性的驗證

  當然,有時候即使建構函式、引數名稱、引數型別、引數值都確定後也不一定會直接鎖定建構函式,不同建構函式的引數為父子關係,所以Spring在最後又做了一次驗證。

5. 根據例項化策略以及得到的建構函式及建構函式引數例項化Bean

1.2 不帶引數的建構函式例項化

  相較於帶有引數的建構函式的例項構造,不帶引數的建構函式的例項化過程是很簡單的,就是直接呼叫例項化策略進行例項化,這裡就不貼程式碼了。

1.3 例項化策略

  現在建構函式以及確定好了,具備了例項化的條件,完全可以使用最簡單的反射方法直接構造例項物件,但是Spring並沒有這麼做:

// SimpleInstantiationStrategy.java
public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {
    // 如果有需要覆蓋或者動態替換的方法則當然需要使用cglib進行動態代理,因為可以在建立代理的同時將動態方法織入類中
    // 但是如果沒有需要動態改變的方法,為了方便直接反射就可以了
    if (beanDefinition.getMethodOverrides().isEmpty()) {
        Constructor<?> constructorToUse;
        synchronized (beanDefinition.constructorArgumentLock) {
            constructorToUse = (Constructor<?>) beanDefinition.resolvedConstructorOrFactoryMethod;
            if (constructorToUse == null) {
                final Class<?> clazz = beanDefinition.getBeanClass();
                if (clazz.isInterface()) {
                    throw new BeanInstantiationException(clazz, "Specified class is an interface");
                }
                try {
                    if (System.getSecurityManager() != null) {
                        constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() {
                            public Constructor<?> run() throws Exception {
                                return clazz.getDeclaredConstructor((Class[]) null);
                            }
                        });
                    }
                    else {
                        constructorToUse =    clazz.getDeclaredConstructor((Class[]) null);
                    }
                    beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse;
                }
                catch (Exception ex) {
                    throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                }
            }
        }
        return BeanUtils.instantiateClass(constructorToUse);
    }
    else {
        // Must generate CGLIB subclass.
        return instantiateWithMethodInjection(beanDefinition, beanName, owner);
    }
}

// CglibSubclassingInstantiationStrategy.java
public Object instantiate(Constructor<?> ctor, Object[] args) {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(this.beanDefinition.getBeanClass());
    enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
    enhancer.setCallbackFilter(new CallbackFilterImpl());
    enhancer.setCallbacks(new Callback[] {
            NoOp.INSTANCE,
            new LookupOverrideMethodInterceptor(),
            new ReplaceOverrideMethodInterceptor()
    });

    return (ctor != null ? enhancer.create(ctor.getParameterTypes(), args) : enhancer.create());
}

  上面的程式中,首先判斷如果beanDefinition.getMethodOverrides()為空也就是使用者沒有使用replace或者lookup的配置方法,那麼直接使用反射的方式,簡單快捷,但是如果使用了這兩個特性,再直接使用反射的方式建立例項就不妥了,因為需要將這兩個配置提供的功能切入進去,所以就必須要使用動態代理的方式將包含兩個特性所對應的邏輯的攔截增強器設定進去,這樣才可以保證在呼叫方法的時候會被相應的攔截器增強,返回值為包含攔截器的代理例項。

2. 屬性注入

  當建立好了bean的例項之後,接著就需要將bean中的屬性進行注入,這部分邏輯是在populateBean()方法中的,具體是如何實現的呢?

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
    PropertyValues pvs = mbd.getPropertyValues();

    if (bw == null) {
        if (!pvs.isEmpty()) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
        }
        else {
            // 沒有可填充的屬性
            return;
        }
    }

    // 給InstantiationAwareBeanPostProcessors最後一次機會在屬性設定前來改變bean
    // 比如:可以用來支援屬性注入的型別
    boolean continueWithPropertyPopulation = true;

    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                // 返回值為是否繼續填充bean
                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                    continueWithPropertyPopulation = false;
                    break;
                }
            }
        }
    }
    // 如果後處理器發出停止填充命令則終止後續的執行
    if (!continueWithPropertyPopulation) {
        return;
    }

    if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
            mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

        // 根據名稱自動注入
        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }

        // 根據型別自動注入
        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }

        pvs = newPvs;
    }
    // 後處理器已經初始化
    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    // 需要依賴檢查
    boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

    if (hasInstAwareBpps || needsDepCheck) {
        PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
        if (hasInstAwareBpps) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    // 對所有需要依賴檢查的屬性進行後處理
                    pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                    if (pvs == null) {
                        return;
                    }
                }
            }
        }
        if (needsDepCheck) {
            // 依賴檢查,對於depends-on屬性
            checkDependencies(beanName, mbd, filteredPds, pvs);
        }
    }
    // 將屬性應用到bean中
    applyPropertyValues(beanName, mbd, bw, pvs);
}

  在populateBean函式中提供了這樣的處理流程

  1. InstantiationAwareBeanPostProcessor處理器的postProcessorAfterInstantiation函式的應用,此函式可以控制程式是否繼續進行屬性填充;
  2. 根據注入型別(byName/byType),提取依賴的bean,並統一存入PropertyValues中;
  3. 應用InstantiationAwareBeanPostProcessor處理器的postProcessorPropertyValues()方法,在屬性獲取完畢並在填充前對屬性進行再次處理,典型應用是RequiredAnnotationBeanPostProcessor類中對屬性的驗證;
  4. 將所有PropertyValues中的屬性填充至BeanWrapper中;

  在上面的步驟中,我們著重分析一下依賴注入(autoworeByName/autowireByType)以及屬性填充。

2.1 autowireByName

  首先來了解一下byName功能是如何實現的:

protected void autowireByName(
        String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
    // 尋找bw中需要依賴注入的屬性
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (String propertyName : propertyNames) {
        if (containsBean(propertyName)) {
            // 遞迴初始化相關的bean
            Object bean = getBean(propertyName);
            pvs.add(propertyName, bean);
            // 註冊依賴
            registerDependentBean(propertyName, beanName);
            if (logger.isDebugEnabled()) {
                logger.debug("Added autowiring by name from bean name '" + beanName +
                        "' via property '" + propertyName + "' to bean named '" + propertyName + "'");
            }
        }
        else {
            if (logger.isTraceEnabled()) {
                logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
                        "' by name: no matching bean found");
            }
        }
    }
}

  這裡無非是在傳入的引數pvs中找出已經載入的bean,並遞迴例項化,進而加入到pvs中。

2.2 autowireByType

  autowireByType與autowireByName在使用和理解層面上覆雜程度相似,但是其實現的複雜程度卻完全不一樣。

protected void autowireByType(
        String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

    TypeConverter converter = getCustomTypeConverter();
    if (converter == null) {
        converter = bw;
    }

    Set<String> autowiredBeanNames = new LinkedHashSet<String>(4);
    // 尋找bw中需要依賴注入的屬性
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (String propertyName : propertyNames) {
        try {
            PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
            // Don't try autowiring by type for type Object: never makes sense,
            // even if it technically is a unsatisfied, non-simple property.
            if (!Object.class.equals(pd.getPropertyType())) {
                // 探測指定屬性的set方法
                MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
                // Do not allow eager init for type matching in case of a prioritized post-processor.
                boolean eager = !PriorityOrdered.class.isAssignableFrom(bw.getWrappedClass());
                DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
                // 解析指定beanName的屬性所匹配的值,並把解析到的屬性名稱儲存在autowiredBeanName中,當屬性存在多個封裝bean時,如:
                // @Autowired private List<A> aList;將會找到所有匹配A型別的bean並將其注入
                Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
                if (autowiredArgument != null) {
                    pvs.add(propertyName, autowiredArgument);
                }
                for (String autowiredBeanName : autowiredBeanNames) {
                    // 註冊依賴
                    registerDependentBean(autowiredBeanName, beanName);
                    if (logger.isDebugEnabled()) {
                        logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" +
                                propertyName + "' to bean named '" + autowiredBeanName + "'");
                    }
                }
                autowiredBeanNames.clear();
            }
        }
        catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
        }
    }
}

  實現根據名稱自動匹配的第一步就是尋找bw中需要依賴注入的屬性,同樣對於根據型別自動匹配的實現來講第一步也是尋找bw中需要依賴注入的屬性,然後遍歷這些屬性並尋找型別匹配的bean,其中最複雜的就是尋找型別匹配的bean。Spring也提供了對集合的型別注入的支援,如使用註解的方式:

@Autowired
private List<Test> tests;

  Spring將會把所有與Test匹配的型別找出來並注入到tests屬性中,正是由於這一因素,所以在autowireByType函式中,新建了區域性變數autowiredBeanNames,用於儲存所有依賴的bean,如果只是對非集合類的屬性注入來說,此屬性並無用處。

  對於尋找型別匹配的邏輯實現封裝在了resolveDependency()函式中:

public Object resolveDependency(DependencyDescriptor descriptor, String beanName,
        Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {

    descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
    if (descriptor.getDependencyType().equals(ObjectFactory.class)) {
        // ObjectFactory類注入的特殊處理
        return new DependencyObjectFactory(descriptor, beanName);
    }
    else if (descriptor.getDependencyType().equals(javaxInjectProviderClass)) {
        // javaxInjectProviderClass類注入的特殊處理
        return new DependencyProviderFactory().createDependencyProvider(descriptor, beanName);
    }
    else {
        // 通用處理邏輯
        return doResolveDependency(descriptor, descriptor.getDependencyType(), beanName, autowiredBeanNames, typeConverter);
    }
}

protected Object doResolveDependency(DependencyDescriptor descriptor, Class<?> type, String beanName,
        Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
    // 用於支援Spring中新增的註解@Value
    Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
    if (value != null) {
        if (value instanceof String) {
            String strVal = resolveEmbeddedValue((String) value);
            BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
            value = evaluateBeanDefinitionString(strVal, bd);
        }
        TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
        return (descriptor.getField() != null ?
                converter.convertIfNecessary(value, type, descriptor.getField()) :
                converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
    }
    // 如果解析器沒有成功解析,則需要考慮各種情況
    // 屬性時陣列型別
    if (type.isArray()) {
        Class<?> componentType = type.getComponentType();
        // 根據屬性型別找到beanFactory中所有型別的匹配bean,
        // 返回值的構成為:key=匹配的beanName,value=beanName 對應的例項化後的bean(通過getBean(beanName)返回)
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType, descriptor);
        if (matchingBeans.isEmpty()) {
            // 如果autowire的require屬性為true而找到的匹配項卻為空則只能丟擲異常
            if (descriptor.isRequired()) {
                raiseNoSuchBeanDefinitionException(componentType, "array of " + componentType.getName(), descriptor);
            }
            return null;
        }
        if (autowiredBeanNames != null) {
            autowiredBeanNames.addAll(matchingBeans.keySet());
        }
        TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
        // 通過轉換器將bean的值轉換為對應的type型別
        return converter.convertIfNecessary(matchingBeans.values(), type);
    }
    // 屬性是Collection型別
    else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
        Class<?> elementType = descriptor.getCollectionType();
        if (elementType == null) {
            if (descriptor.isRequired()) {
                throw new FatalBeanException("No element type declared for collection [" + type.getName() + "]");
            }
            return null;
        }
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType, descriptor);
        if (matchingBeans.isEmpty()) {
            if (descriptor.isRequired()) {
                raiseNoSuchBeanDefinitionException(elementType, "collection of " + elementType.getName(), descriptor);
            }
            return null;
        }
        if (autowiredBeanNames != null) {
            autowiredBeanNames.addAll(matchingBeans.keySet());
        }
        TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
        return converter.convertIfNecessary(matchingBeans.values(), type);
    }
    // 屬性是Map型別
    else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
        Class<?> keyType = descriptor.getMapKeyType();
        if (keyType == null || !String.class.isAssignableFrom(keyType)) {
            if (descriptor.isRequired()) {
                throw new FatalBeanException("Key type [" + keyType + "] of map [" + type.getName() +
                        "] must be assignable to [java.lang.String]");
            }
            return null;
        }
        Class<?> valueType = descriptor.getMapValueType();
        if (valueType == null) {
            if (descriptor.isRequired()) {
                throw new FatalBeanException("No value type declared for map [" + type.getName() + "]");
            }
            return null;
        }
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, descriptor);
        if (matchingBeans.isEmpty()) {
            if (descriptor.isRequired()) {
                raiseNoSuchBeanDefinitionException(valueType, "map with value type " + valueType.getName(), descriptor);
            }
            return null;
        }
        if (autowiredBeanNames != null) {
            autowiredBeanNames.addAll(matchingBeans.keySet());
        }
        return matchingBeans;
    }
    else {
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
        if (matchingBeans.isEmpty()) {
            if (descriptor.isRequired()) {
                raiseNoSuchBeanDefinitionException(type, "", descriptor);
            }
            return null;
        }
        if (matchingBeans.size() > 1) {
            String primaryBeanName = determinePrimaryCandidate(matchingBeans, descriptor);
            if (primaryBeanName == null) {
                throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet());
            }
            if (autowiredBeanNames != null) {
                autowiredBeanNames.add(primaryBeanName);
            }
            return matchingBeans.get(primaryBeanName);
        }
        // 已經可以確定只有一個匹配項
        Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
        if (autowiredBeanNames != null) {
            autowiredBeanNames.add(entry.getKey());
        }
        return entry.getValue();
    }
}

  這裡首先嚐試使用解析器進行解析,如果解析器沒有成功解析,那麼可能是使用預設的解析器沒有做任何處理,或者是使用了自定義的解析器,但是對於集合等型別來說並不在解析範圍之內,所以會再次對不同集合型別進行不同情況的處理,雖然對於不同集合型別處理方式不一致,但是大致思路是很相似的,所以這裡只分析一下對陣列型別的解析:

  • 首先獲取陣列封裝的型別;
  • 根據屬性型別找到beanFactory中所有型別的匹配bean;
  • 將找到的所有匹配的beanName加入到傳入的autowiredBeanNames中;
  • 對找到的所有匹配的bean轉換為對應的type型別並返回;

2.3 applyPropertyValues

  到這裡,已經完成了對所有注入屬性的獲取,但是獲取的屬性是以PropertyValues形式存在的,還沒有應用到已經例項化的bean中,這一工作是在applyPropertyValues中:

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
    if (pvs == null || pvs.isEmpty()) {
        return;
    }

    MutablePropertyValues mpvs = null;
    List<PropertyValue> original;

    if (System.getSecurityManager() != null) {
        if (bw instanceof BeanWrapperImpl) {
            ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
        }
    }

    if (pvs instanceof MutablePropertyValues) {
        mpvs = (MutablePropertyValues) pvs;
        // 如果mpvs中的值已經被轉換為對應的型別那麼可以直接設定到beanwapper中
        if (mpvs.isConverted()) {
            // Shortcut: use the pre-converted values as-is.
            try {
                bw.setPropertyValues(mpvs);
                return;
            }
            catch (BeansException ex) {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Error setting property values", ex);
            }
        }
        original = mpvs.getPropertyValueList();
    }
    else {
        // 如果pvs並不是使用MutablePropertyValues封裝的型別,那麼直接使用原始的屬性獲取方法
        original = Arrays.asList(pvs.getPropertyValues());
    }

    TypeConverter converter = getCustomTypeConverter();
    if (converter == null) {
        converter = bw;
    }
    // 獲取對應的解析器
    BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

    // Create a deep copy, resolving any references for values.
    List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
    boolean resolveNecessary = false;
    // 遍歷屬性,將屬性轉換為對應類的對應屬性的型別
    for (PropertyValue pv : original) {
        if (pv.isConverted()) {
            deepCopy.add(pv);
        }
        else {
            String propertyName = pv.getName();
            Object originalValue = pv.getValue();
            Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
            Object convertedValue = resolvedValue;
            boolean convertible = bw.isWritableProperty(propertyName) &&
                    !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
            if (convertible) {
                convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
            }
            // Possibly store converted value in merged bean definition,
            // in order to avoid re-conversion for every created bean instance.
            if (resolvedValue == originalValue) {
                if (convertible) {
                    pv.setConvertedValue(convertedValue);
                }
                deepCopy.add(pv);
            }
            else if (convertible && originalValue instanceof TypedStringValue &&
                    !((TypedStringValue) originalValue).isDynamic() &&
                    !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
                pv.setConvertedValue(convertedValue);
                deepCopy.add(pv);
            }
            else {
                resolveNecessary = true;
                deepCopy.add(new PropertyValue(pv, convertedValue));
            }
        }
    }
    if (mpvs != null && !resolveNecessary) {
        mpvs.setConverted();
    }

    // Set our (possibly massaged) deep copy.
    try {
        bw.setPropertyValues(new MutablePropertyValues(deepCopy));
    }
    catch (BeansException ex) {
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Error setting property values", ex);
    }
}

3. 初始bean

  在bean配置時bean中有一個init-method的屬性,這個屬性的作用是在bean初始化時呼叫init-method屬性指定的方法來根據使用者業務執行相應的初始化工作,初始化的工作是在bean完成例項化並且進行了屬性填充之後進行的。實現這個功能的程式碼在initializeBean()方法中:

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged(new PrivilegedAction<Object>() {
            public Object run() {
                invokeAwareMethods(beanName, bean);
                return null;
            }
        }, getAccessControlContext());
    }
    else {
        // 對特殊的bean的處理:Aware、BeanClassLoaderAware、BeanFactoryAware
        invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        // 應用後處理器
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        // 啟用使用者自定義的init方法
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
    }

    if (mbd == null || !mbd.isSynthetic()) {
        // 應用後處理器
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    return wrappedBean;
}

  這裡除了呼叫使用者指定的方法執行初始化,還做了其它一些操作,主要有啟用Aware方法、應用後處理器、啟用自定義的init方法。

3.1 啟用Aware方法

  我們先了解一下Aware的使用,Spring中提供了一些Aware相關介面,比如BeanFactoryAware、ApplicationContextAware、ResourceLoaderAware、ServletContextAware等,實現這些Aware介面的bean在被初始化之後,可以取得一些相對應的資源,例如實現了BeanFactoryAware介面的bean在初始化後,Spring容器將會注入BeanFactory的例項,而實現了ApplicationContextAware介面的bean,在bean被初始化後,將會被注入ApplicationContext的例項等。這裡先通過示例方法來了解一下Aware的使用:

// 定義普通bean
public class Hello {
    public void say(){
        System.out.println("hello");
    }
}

// 定義BeanFactoryAware型別的bean
public class Test implements BeanFactoryAware {
    private BeanFactory beanFactory;

    // 宣告bean的時候Spring會自動注入BeanFactory
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    public void testAware() { 
        // 通過hello這個bean id從beanFactory獲取例項
        Hello hello = (Hello)beanFactory.getBean("hello");
        hello.say();
    }
}

// 使用main方法測試
public static void main(String[] args){
    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    Test test = (Test)ctx.getBean("test");
    test.testAware();
}

  執行測試類,控制檯會輸出:hello

  按照上面的方法我們可以獲取到Spring中BeanFactory,並且可以根據BeanFactory獲取所有bean,以及進行相關設定。當然還有其他Aware的使用方法都大同小異,這裡就不一一列舉了。我們接下來看一下Spring是如何啟用Aware方法的。

private void invokeAwareMethods(final String beanName, final Object bean) {
    if (bean instanceof Aware) {
        if (bean instanceof BeanNameAware) {
            ((BeanNameAware) bean).setBeanName(beanName);
        }
        if (bean instanceof BeanClassLoaderAware) {
            ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
        }
        if (bean instanceof BeanFactoryAware) {
            ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
        }
    }
}

  這個就是直接判斷是否實現介面,然後呼叫對應的set方法。

3.2 處理器的應用

  BeanPostProcessor相信用過Spring的同學都聽過,這是Spring中開放式架構中一個必不可少的亮點,給使用者充足的許可權去更改或者擴充套件Spring,而除了BeanPostProcessor外還有很多其他的PostProcessor,都是繼承自BeanPostProcessor,給使用者提供介面進行擴充套件,這又是如何實現的呢?其實就是在呼叫使用者自定義的init方法之前和之後分別呼叫BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法,使用者可以在這兩個方法中定義自己的業務邏輯。

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

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

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;
}

3.3 啟用自定義的init方法

  由使用者定製的初始化方法除了我們熟知的使用配置init-method外,還有讓自定義的bean實現InitializingBean介面,並在afterPropertiesSet中實現自己的初始化業務邏輯。

  init-method與afterPropertiesSet都是在初始化bean時執行,執行順序是afterPropertiesSet先執行,而init-method後執行。

  在invokeInitMethod()方法中就實現了這兩個步驟的初始化方法呼叫:

protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
        throws Throwable {
    // 首先會檢查是否是InitializingBean,如果是的話需要呼叫afterPropertiesSet方法
    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
        if (logger.isDebugEnabled()) {
            logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
        }
        if (System.getSecurityManager() != null) {
            try {
                AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                    public Object run() throws Exception {
                        ((InitializingBean) bean).afterPropertiesSet();
                        return null;
                    }
                }, getAccessControlContext());
            }
            catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }
        else {
            // 屬性初始化後的處理
            ((InitializingBean) bean).afterPropertiesSet();
        }
    }

    if (mbd != null) {
        String initMethodName = mbd.getInitMethodName();
        if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                !mbd.isExternallyManagedInitMethod(initMethodName)) {
            // 呼叫自定義初始化方法
            invokeCustomInitMethod(beanName, bean, mbd);
        }
    }
}

4. 註冊DisposableBean

  Spring中不但提供了對於初始化方法的擴充套件入口,同樣也提供了銷燬方法的擴充套件入口,對於銷燬方法的擴充套件,除了我們熟知的配置屬性destroy-method方法外,使用者還可以註冊後處理器DestructionAwareBeanPostProcessor來統一處理bean的銷燬方法,程式碼如下: 

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
    AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
    if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
        if (mbd.isSingleton()) {
            // 單例模式下注冊需要銷燬的bean,此方法中會處理實現DisposableBean的bean,
            // 並且所有的bean使用DestructionAwareBeanPostProcessors處理
            // DisposableBean DestructionAwareBeanPostProcessors
            registerDisposableBean(beanName,
                    new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
        }
        else {
            // 自定義scope的處理
            Scope scope = this.scopes.get(mbd.getScope());
            if (scope == null) {
                throw new IllegalStateException("No Scope registered for scope '" + mbd.getScope() + "'");
            }
            scope.registerDestructionCallback(beanName,
                    new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
        }
    }
}

5. 總結

  本文篇幅稍長,詳細分析了建立bean的各個步驟,包括構造bean、屬性注入、初始化bean、註冊DisposableBean,其中構造bean和屬性注入的邏輯比較複雜,初始化和註冊DisposableBean相對簡單。

構造bean大致流程如下(帶引數建構函式):

  • 建構函式引數的確定
  • 建構函式的確定
  • 建構函式的確定
  • 根據例項化策略以及得到的建構函式及建構函式引數例項化Bean

屬性注入大致流程如下:

  • 尋找需要依賴注入的屬性
  • 根據名稱/型別尋找匹配的屬性bean
  • 注入屬性

  歷經艱難,至此bean的載入就完成了,到這裡應該也能夠感受到一個簡單IOC思想在Spring那裡實現起來有多複雜了!能看到這裡的同學都不容易,為自己點個贊吧!

相關文章