[Spring]Spring是如何做Bean屬性填充的-populateBean

前言

在前面的doCreateBean方法中板惑,我們了解到奋刽,populateBean是負(fù)責(zé)填充Bean實(shí)例屬性的楔敌。此時(shí)Bean中需要依賴注入的成員已經(jīng)在applyMergedBeanDefinitionPostProcessors中被對(duì)應(yīng)的后置處理器進(jìn)行了存儲(chǔ)葫隙,最終的成員被封裝到了AutowiredAnnotationBeanPostProcessor#injectionMetadataCache這個(gè)集合中.

1. Dependencies和Dependency Injection

很多人可能還不清除什么是依賴和依賴注入.這是理解Spring IoC的一個(gè)核心概念.下面簡(jiǎn)單從代碼的角度談?wù)勈裁词且蕾嚭鸵蕾囎⑷?

  • 一個(gè)簡(jiǎn)單的MVC登陸入口
@RestController
@RequestMapping("/web")
public class UserController {

    @Autowired
    @Qualifier("normalUserService")
    private UserService userService;

    /**
     * 用戶登陸入口
     */
    @PostMapping("/login")
    public void login(User user) {
        userService.login(user);
    }
}

軟件架構(gòu)設(shè)計(jì)原則中要求面向接口編程,為此MVC架構(gòu)中往往采取的是上面代碼展示的這種結(jié)構(gòu)叠穆,UserController依賴于UserService接口的實(shí)現(xiàn)類(lèi).此時(shí),UserController就與UserService直接形成了依賴關(guān)系.
此時(shí)萍恕,如果沒(méi)有Spring,我們有三種方式去將UserService注入進(jìn)來(lái):

  1. 每次調(diào)用login的時(shí)候,new UserService();
  2. 通過(guò)setter的方式進(jìn)行注入.即UserController中提供setUserService(UserService userService).
  3. 通過(guò)構(gòu)造方法進(jìn)行注入,public UserController(UserService userService).

其中,new的方式是耦合度較高的做法轮洋。所以在Spring中,提供了構(gòu)造注入setter注入的方式來(lái)落地IoC思想(Inversion of Control).
與用戶主動(dòng)調(diào)用的方式不同抬旺,在Spring框架中弊予,往往只需要聲明好依賴關(guān)系,框架就會(huì)自動(dòng)生成好用戶需要的Java對(duì)象,這就是所謂的Bean.我們一般將UserController中去注入U(xiǎn)serService這個(gè)過(guò)程稱(chēng)為依賴注入开财,即專(zhuān)業(yè)術(shù)語(yǔ)上的DI(Dependency Injection).

2. 自動(dòng)裝配

@Autowired注解和@Resource注解都是自動(dòng)裝配的代表,思考一下,自動(dòng)裝配大概是什么過(guò)程?
從前面的文章中我們學(xué)習(xí)了汉柒,Spring將Java對(duì)象中的信息抽象成了BeanDefinition,最后通過(guò)getBean方法來(lái)加載非延遲加載的單例Bean,每當(dāng)getBean裝配完一個(gè)Bean之后,就會(huì)添加到單例緩存中.
那么自動(dòng)裝配的過(guò)程责鳍,就是按規(guī)則(如果指定)從容器中獲取到依賴的Bean碾褂,然后通過(guò)反射進(jìn)行賦值完成裝配的的過(guò)程.

3. populateBean的總體流程

  • 激活I(lǐng)nstantiationAwareBeanPostProcessor后置處理器的InstantiationAwareBeanPostProcessor方法: 在實(shí)例化bean之后,Spring屬性填充之前執(zhí)行的鉤子方法,
    這是在Spring的自動(dòng)裝配開(kāi)始之前對(duì)該bean實(shí)例執(zhí)行自定義字段注入的回調(diào),也是最后一次機(jī)會(huì)在自動(dòng)裝配前修改Bean的屬性值。
  • 解析依賴注入的方式,將屬性裝配到PropertyValues中: resolvedAutowireMode.
  • 激活I(lǐng)nstantiationAwareBeanPostProcessor#postProcessProperties: 對(duì)@AutoWired標(biāo)記的屬性進(jìn)行依賴注入.
  • 依賴檢查: checkDependencies.
  • 將解析的值用BeanWrapper進(jìn)行包裝: applyPropertyValues.
3.1 InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
  • AbstractAutowireCapableBeanFactory#populateBean
        // InstantiationAwareBeanPostProcessors最后一次進(jìn)行對(duì)bean的屬性修改
        // 采用職責(zé)鏈的方式對(duì)所有實(shí)現(xiàn)了InstantiationAwareBeanPostProcessor的后置處理器調(diào)用.
        // 直到某個(gè)InstantiationAwareBeanPostProcessor在postProcessAfterInstantiation中返回了false
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    // 如果返回了false,直接中斷,不進(jìn)行下面的操作
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                        return;
                    }
                }
            }
        }

populateBean中历葛,首先會(huì)經(jīng)過(guò)判空校驗(yàn)正塌,校驗(yàn)通過(guò)后.
檢查用戶是否有注冊(cè) InstantiationAwareBeanPostProcessor,如果有嘀略,使用責(zé)任鏈模式激活這些后置器中的postProcessAfterInstantiation方法,如果某個(gè)后置處理器返回了false,那么Spring就不會(huì)執(zhí)行框架的自動(dòng)裝配邏輯了.官方的建議是不建議去擴(kuò)展此后置處理器,而是推薦擴(kuò)展自BeanPostProcessor或從InstantiationAwareBeanPostProcessorAdapter派生.

3.2 根據(jù)注入方式解析屬性到PropertyValues
        // 這里的pvs其實(shí)是一個(gè)MutablePropertyValues實(shí)例
        // 提供對(duì)屬性的讀寫(xiě)操作實(shí)現(xiàn)乓诽,同時(shí)可以通過(guò)構(gòu)造函數(shù)實(shí)現(xiàn)深拷貝
        // 獲取BeanDefinition里面為Bean設(shè)置的屬性值
        PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
        // 根據(jù)Bean配置的依賴注入方式完成注入,默認(rèn)是0帜羊,即不走以下邏輯
        // 如果設(shè)置了相關(guān)的依賴裝配方式,會(huì)遍歷Bean的屬性鸠天,根據(jù)type或者name完成相應(yīng)注入
        int resolvedAutowireMode = mbd.getResolvedAutowireMode();
        if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
            // Add property values based on autowire by name if applicable.
            // 根據(jù)beanName進(jìn)行autowired自動(dòng)裝配邏輯
            if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
                autowireByName(beanName, mbd, bw, newPvs);
            }
            // Add property values based on autowire by type if applicable.
            // 根據(jù)Type進(jìn)行autowired自動(dòng)裝配邏輯
            if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
                autowireByType(beanName, mbd, bw, newPvs);
            }
            pvs = newPvs;
        }
  1. 首先從BeanDefinition中取出propertyValues,具體的調(diào)用方法在AbstractBeanDefinition#getPropertyValues中,返回的類(lèi)型為MutablePropertyValues.
  2. 解析依賴裝配入的方式.在AutowireCapableBeanFactory接口中聲明了5種依賴注入的方式:
resolvedAutowireMode 依賴注入方式 描述
0 AUTOWIRE_NO 沒(méi)有顯式配置上裝配的方式
1 AUTOWIRE_BY_NAME 按beanName進(jìn)行裝配
2 AUTOWIRE_BY_TYPE 按type進(jìn)行裝配
3 AUTOWIRE_CONSTRUCTOR 在構(gòu)造函數(shù)中進(jìn)行裝配
4 AUTOWIRE_AUTODETECT 通過(guò)內(nèi)省bean類(lèi)確定適當(dāng)?shù)淖詣?dòng)裝配策略,Spring已經(jīng)將其標(biāo)注為@Deprecated

一般以注解的形式讼育,默認(rèn)都解析為0,也就是沒(méi)有顯式配置自動(dòng)裝配策略.
什么情況會(huì)進(jìn)入if條件中的代碼塊稠集,通常是在XML配置文件中顯式指定了autowired或者在Java配置類(lèi)中@Bean上奶段,聲明autowired.
簡(jiǎn)單給個(gè)示例:

    @Bean(autowire = Autowire.BY_NAME)
3.3 InstantiationAwareBeanPostProcessor#postProcessProperties

如果沒(méi)有顯式聲明自動(dòng)裝配的方式(@Autowired注解),那么就會(huì)使用到InstantiationAwareBeanPostProcessor這個(gè)后置處理器的postProcessProperties方法.

        // 容器是否注冊(cè)了InstantiationAwareBeanPostProcessors
        boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
        // 是否進(jìn)行依賴檢查剥纷,默認(rèn)為false
        boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

        PropertyDescriptor[] filteredPds = null;
        if (hasInstAwareBpps) {
            if (pvs == null) {
                pvs = mbd.getPropertyValues();
            }
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    // 對(duì)@AutoWired標(biāo)記的屬性進(jìn)行依賴注入
                    PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                    if (pvsToUse == null) {
                        if (filteredPds == null) {
                            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                        }
                        // 對(duì)解析完未設(shè)置的屬性再進(jìn)行處理
                        pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                        if (pvsToUse == null) {
                            return;
                        }
                    }
                    pvs = pvsToUse;
                }
            }
        }
  • AutowiredAnnotationBeanPostProcessor#postProcessProperties
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
        // 獲取指定類(lèi)中被@Autowired注解標(biāo)記的metadata.
        // metadata在實(shí)例化后的applyMergedBeanDefinitionPostProcessors中進(jìn)行了存儲(chǔ)
        // 此時(shí)的findAutowiringMetadata是從injectionMetadataCache緩存中讀取metadata
        InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
        try {
            // 對(duì)Bean的屬性進(jìn)行自動(dòng)注入
            metadata.inject(bean, beanName, pvs);
        }
        catch (BeanCreationException ex) {
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
        }
        return pvs;
    }

在前面的doCreateBean中我們對(duì)applyMergedBeanDefinitionPostProcessors進(jìn)行了分析忧饭,在它的postProcessMergedBeanDefinition中已經(jīng)調(diào)用了 findAutowiringMetadata這個(gè)方法對(duì)Bean上被@Autowired標(biāo)記的成員進(jìn)行了存儲(chǔ),此時(shí)已經(jīng)進(jìn)入到了屬性填充階段筷畦,從injectionMetadataCache這個(gè)緩存區(qū)即可獲取InjectionMetadata類(lèi)型的metadata,即依賴注入的元數(shù)據(jù).
InjectionMetadata中提供了一個(gè)inject方法词裤,執(zhí)行自動(dòng)注入依賴的邏輯.

3.3.1 org.springframework.beans.factory.annotation.InjectionMetadata#inject
    public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
        Collection<InjectedElement> checkedElements = this.checkedElements;
        Collection<InjectedElement> elementsToIterate =
                (checkedElements != null ? checkedElements : this.injectedElements);
        if (!elementsToIterate.isEmpty()) {
            for (InjectedElement element : elementsToIterate) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Processing injected element of bean '" + beanName + "': " + element);
                }
                // 調(diào)用InjectedElement#inject,這里是多態(tài)的實(shí)現(xiàn)
                // @Autowired關(guān)注AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement.inject
                element.inject(target, beanName, pvs);
            }
        }
    }

這里邏輯比較清晰,查看當(dāng)前的checkedElements是否為空鳖宾,如果為空,解析injectedElements.然后遍歷對(duì)element執(zhí)行inject操作.

  • AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
        protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
            // 當(dāng)前存儲(chǔ)的需要注入的成員
            Field field = (Field) this.member;
            Object value;
            // 如果該成員的值被緩存了吼砂,從緩存中獲取
            if (this.cached) {
                // 最終調(diào)用DefaultListableBeanFactory的resolveDependency
                value = resolvedCachedArgument(beanName, this.cachedFieldValue);
            }
            else {
                // 為該成員創(chuàng)建一個(gè)DependencyDescriptor.
                DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
                // 設(shè)置當(dāng)前bean的Class
                desc.setContainingClass(bean.getClass());
                Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
                Assert.state(beanFactory != null, "No BeanFactory available");
                // 獲取類(lèi)型轉(zhuǎn)換器
                TypeConverter typeConverter = beanFactory.getTypeConverter();
                try {
                    // 最終調(diào)用DefaultListableBeanFactory的resolveDependency
                    value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
                }
                catch (BeansException ex) {
                    throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
                }
                synchronized (this) {
                    // 如果成員變量的值沒(méi)有緩存
                    if (!this.cached) {
                        // 成員變量的值不為null,并且required==true
                        if (value != null || this.required) {
                            this.cachedFieldValue = desc;
                            // 注冊(cè)依賴關(guān)系
                            registerDependentBeans(beanName, autowiredBeanNames);
                            if (autowiredBeanNames.size() == 1) {
                                String autowiredBeanName = autowiredBeanNames.iterator().next();
                                // 依賴對(duì)象類(lèi)型和字段類(lèi)型匹配,默認(rèn)按類(lèi)型注入
                                if (beanFactory.containsBean(autowiredBeanName) &&
                                        beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
                                    this.cachedFieldValue = new ShortcutDependencyDescriptor(
                                            desc, autowiredBeanName, field.getType());
                                }
                            }
                        }
                        else {
                            this.cachedFieldValue = null;
                        }
                        this.cached = true;
                    }
                }
            }
            if (value != null) {
                ReflectionUtils.makeAccessible(field);
                // 調(diào)用反射進(jìn)行賦值
                field.set(bean, value);
            }
        }
    }

OK,來(lái)到解析依賴的關(guān)鍵步驟了.

  1. 先嘗試從緩存中獲取該依賴對(duì)應(yīng)的Bean.
  2. 如果BeanFactory中沒(méi)有該依賴對(duì)應(yīng)的Bean.為該成員創(chuàng)建一個(gè)DependencyDescriptor,然后調(diào)用beanFactory.resolveDependency來(lái)加載Bean.
  3. 注冊(cè)Bean之間的依賴關(guān)系.
  4. 將獲取到的Bean調(diào)用反射進(jìn)行填充.field.set(bean, value)鼎文,注意在這一步之前渔肩,Spring對(duì)field的權(quán)限進(jìn)行了設(shè)置,field.setAccessible(true)

其中,自動(dòng)裝配的邏輯就封裝在了beanFactory.resolveDependency中.繼續(xù)前進(jìn)一探究竟.

3.3.2 DefaultListableBeanFactory#resolveDependency
    public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
            @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

        descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
        if (Optional.class == descriptor.getDependencyType()) {
            return createOptionalDependency(descriptor, requestingBeanName);
        }
        else if (ObjectFactory.class == descriptor.getDependencyType() ||
                ObjectProvider.class == descriptor.getDependencyType()) {
            return new DependencyObjectProvider(descriptor, requestingBeanName);
        }
        else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
            return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
        }
        else {
            Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
                    descriptor, requestingBeanName);
            if (result == null) {
                // 解析依賴
                result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
            }
            return result;
        }
    }

這里Spring會(huì)對(duì)依賴做一些適配拇惋,我們主要看doResolveDependency這個(gè)解析依賴的方法.

  • DefaultListableBeanFactory#doResolveDependency
    public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
            @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

        InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
        try {
            // 從容器中獲取依賴,在debug環(huán)境下點(diǎn)進(jìn)去會(huì)發(fā)現(xiàn)周偎,會(huì)到達(dá)beanFactory.getBean()中
            Object shortcut = descriptor.resolveShortcut(this);
            // 如果可以從容器中獲取到bean,直接返回
            if (shortcut != null) {
                return shortcut;
            }

            Class<?> type = descriptor.getDependencyType();
            // 處理@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());
                try {
                    return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
                }
                catch (UnsupportedOperationException ex) {
                    // A custom TypeConverter which does not support TypeDescriptor resolution...
                    return (descriptor.getField() != null ?
                            converter.convertIfNecessary(value, type, descriptor.getField()) :
                            converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
                }
            }
            // 如果標(biāo)識(shí)@Autowired注解的成員變量是復(fù)合類(lèi)型,如:數(shù)組撑帖、List蓉坎、Map等.
            // 從這里獲取@Autowired中的值
            Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
            if (multipleBeans != null) {
                return multipleBeans;
            }
            // 如果被@Autowired標(biāo)注的成員并非復(fù)合對(duì)象
            Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
            if (matchingBeans.isEmpty()) {
                // 如果找不到,校驗(yàn)當(dāng)前是否標(biāo)注了required為true.
                if (isRequired(descriptor)) {
                    // 如果@Autowired標(biāo)注了(required = true),但是無(wú)法匹配到相應(yīng)的bean,拋出NoSuchBeanDefinitionException異常
                    raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
                }
                return null;
            }

            String autowiredBeanName;
            Object instanceCandidate;
            // 如果匹配到了不止一個(gè)Bean,看看是否標(biāo)注了@Primary和@Priority
            if (matchingBeans.size() > 1) {
                autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
                if (autowiredBeanName == null) {
                    if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
                        // 如果沒(méi)有聲明,則直接拋出NoUniqueBeanDefinitionException
                        return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
                    }
                    else {
                        // In case of an optional Collection/Map, silently ignore a non-unique case:
                        // possibly it was meant to be an empty collection of multiple regular beans
                        // (before 4.3 in particular when we didn't even look for collection beans).
                        return null;
                    }
                }
                instanceCandidate = matchingBeans.get(autowiredBeanName);
            }
            else {
                // We have exactly one match.
                Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
                // key為被依賴的候選者名稱(chēng),例如:UserController依賴UserService.
                // 此時(shí)autowiredBeanName=userService
                autowiredBeanName = entry.getKey();
                // Class,先選舉胡嘿,選舉結(jié)束之后再進(jìn)行實(shí)例化
                instanceCandidate = entry.getValue();
            }

            if (autowiredBeanNames != null) {
                autowiredBeanNames.add(autowiredBeanName);
            }
            if (instanceCandidate instanceof Class) {
                // 將獲取到的候選者Class進(jìn)行g(shù)etBean
                instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
            }
            Object result = instanceCandidate;
            if (result instanceof NullBean) {
                if (isRequired(descriptor)) {
                    raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
                }
                result = null;
            }
            if (!ClassUtils.isAssignableValue(type, result)) {
                throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
            }
            return result;
        }
        finally {
            ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
        }
    }

這里的代碼邏輯就跟我們平時(shí)編程是息息相關(guān)的了蛉艾。

  1. 調(diào)用descriptor.resolveShortcut查看當(dāng)前工廠是否已經(jīng)加載過(guò)相同的Bean,如果是則直接返回.
  2. 處理@Value解析的邏輯.
  3. 如果當(dāng)前注入的是復(fù)合對(duì)象,調(diào)用resolveMultipleBeans.
  4. 如果只是注入普通的Bean對(duì)象,查找符合條件的候選名單.返回一個(gè)Map.
    為什么返回一個(gè)Map呢,這是因?yàn)橐粋€(gè)接口可以有多個(gè)實(shí)現(xiàn)類(lèi),按照類(lèi)型查找衷敌,就會(huì)把實(shí)現(xiàn)該接口的實(shí)現(xiàn)類(lèi)返回.在應(yīng)對(duì)這種多個(gè)候選Bean的時(shí)候勿侯,Spring會(huì)去判斷是是否聲明了@Primary注解或者@Order注解來(lái)決定注入哪個(gè)Bean.如果沒(méi)有聲明,再判斷是否聲明了required=false)缴罗,如果required為默認(rèn)的,則拋出NoUniqueBeanDefinitionException異常助琐。
  5. 匹配完候選名單后,對(duì)候選名單進(jìn)行resolveCandidate操作面氓,點(diǎn)進(jìn)去方法會(huì)發(fā)現(xiàn)兵钮,其實(shí)是調(diào)用了beanFactory.getBean(beanName).

什么是復(fù)合對(duì)象?
Spring不僅僅只可以注入單一的Bean對(duì)象沟堡,還支持?jǐn)?shù)組、集合矢空、Stream航罗、Map等方式的注入.

3.3.3 如果Autowired按byType的方式無(wú)法挑選出最合適的Bean如何進(jìn)行降級(jí)處理

答案在determineAutowireCandidate中,在通過(guò)byType的方式無(wú)法選出最合適的Bean后,Spring會(huì)用byName的方式對(duì)比出當(dāng)前屬性名與候選Bean名單中的candidateName是否匹配來(lái)做最終的處理.

  • DefaultListableBeanFactory#determineAutowireCandidate
    protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
        Class<?> requiredType = descriptor.getDependencyType();
        // 根據(jù)@Primary注解標(biāo)簽來(lái)選擇最優(yōu)解
        String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
        if (primaryCandidate != null) {
            return primaryCandidate;
        }
        // 根據(jù)@Order屁药、@Priority以及實(shí)現(xiàn)了Order接口的序號(hào)來(lái)最合適的Bean(序號(hào)越小越合適)進(jìn)行注入
        String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
        if (priorityCandidate != null) {
            return priorityCandidate;
        }
        // Fallback
        for (Map.Entry<String, Object> entry : candidates.entrySet()) {
            String candidateName = entry.getKey();
            Object beanInstance = entry.getValue();
            // 如果無(wú)法通過(guò)上面兩個(gè)方法找到最優(yōu)解的Bean:
            // 如果類(lèi)型已經(jīng)在resolvableDependencies中粥血,直接返回已經(jīng)注冊(cè)的對(duì)象.
            // 如果byType的方式找不到,嘗試使用byName的方式尋找依賴
            // 如果屬性名稱(chēng)和某個(gè)候選者的Bean名稱(chēng)或者別名一致,則直接將該Bean返回
            if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
                    matchesBeanName(candidateName, descriptor.getDependencyName())) {
                return candidateName;
            }
        }
        return null;
    }

假設(shè)UserService有兩個(gè)實(shí)現(xiàn)類(lèi),VipUserService的beanName被主動(dòng)聲明為vip,NormalUserService聲明為normal,那么你在Controller中可以這樣寫(xiě)來(lái)注入VipUserService:

@Autowired
UserService vip;

4. 依賴檢查

Spring在最新的版本已經(jīng)不推薦使用,所以這里我們也不做重點(diǎn)講解.

5. 將解析的值用BeanWrapper進(jìn)行包裝-applyPropertyValues.

通過(guò)注解形式配置的Bean并不會(huì)往pvs中填充值酿箭,筆者在一些書(shū)上看到都是重點(diǎn)解析這個(gè)方法复亏,目前Spring5.1的版本進(jìn)行debug未發(fā)現(xiàn)進(jìn)入到這個(gè)方法中,所以也不做詳細(xì)的講解缭嫡。我更傾向于這是為了兼容XML的做法留下的方法.

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

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

        MutablePropertyValues mpvs = null;
        List<PropertyValue> original;

        if (pvs instanceof MutablePropertyValues) {
            mpvs = (MutablePropertyValues) pvs;
            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 {
            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<>(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);
        }
    }

    /**
     * Convert the given value for the specified target property.
     */
    @Nullable
    private Object convertForProperty(
            @Nullable Object value, String propertyName, BeanWrapper bw, TypeConverter converter) {

        if (converter instanceof BeanWrapperImpl) {
            return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName);
        }
        else {
            PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
            MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
            return converter.convertIfNecessary(value, pd.getPropertyType(), methodParam);
        }
    }

從XML中配置的<bean>將所有的屬性聲明為了字符串缔御,因此在這里需要做一些類(lèi)型的解析和強(qiáng)轉(zhuǎn).核心方法:

  1. 解析Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
  2. 注入bw.setPropertyValues(new MutablePropertyValues(deepCopy));

總結(jié)

  1. 注解驅(qū)動(dòng)的Bean執(zhí)行屬性填充并不在autowireByNameautowireByType中,而是在AutowiredAnnotationBeanPostProcessor這個(gè)后置處理器的postProcessProperties中.
  2. 在做屬性填充時(shí)妇蛀,如果當(dāng)前的Bean實(shí)例依賴的成員(另一個(gè)Bean)未被加載耕突,會(huì)進(jìn)入選舉候選名單的邏輯中,進(jìn)行各種判斷后,選出最適合的Bean實(shí)例進(jìn)行getBean操作.
  3. @Autowired在進(jìn)行自動(dòng)裝配的過(guò)程中评架,默認(rèn)按照"byType"的方式進(jìn)行Bean加載眷茁,如果出現(xiàn)無(wú)法挑選出合適的Bean的情況,再將屬性名與候選Bean名單中的beanName進(jìn)行對(duì)比.
  4. 正確地聲明@PrimaryOrder等注解讓Bean在多態(tài)的選舉中優(yōu)選勝出.
  5. required=false可以讓程序在找不到Bean的時(shí)候不拋出異常纵诞,但是調(diào)用期間還是會(huì)報(bào)錯(cuò)(緩兵之計(jì)),不建議這種使用.
  6. XML的自動(dòng)裝配模式與注解驅(qū)動(dòng)的模式在代碼上是不同的分岔.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末上祈,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子浙芙,更是在濱河造成了極大的恐慌登刺,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嗡呼,死亡現(xiàn)場(chǎng)離奇詭異纸俭,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)晤锥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)掉蔬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人矾瘾,你說(shuō)我怎么就攤上這事〖簦” “怎么了壕翩?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)傅寡。 經(jīng)常有香客問(wèn)我放妈,道長(zhǎng)北救,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任芜抒,我火速辦了婚禮珍策,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘宅倒。我一直安慰自己攘宙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布拐迁。 她就那樣靜靜地躺著蹭劈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪线召。 梳的紋絲不亂的頭發(fā)上铺韧,一...
    開(kāi)封第一講書(shū)人閱讀 51,562評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音缓淹,去河邊找鬼哈打。 笑死,一個(gè)胖子當(dāng)著我的面吹牛讯壶,可吹牛的內(nèi)容都是我干的前酿。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼鹏溯,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼罢维!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起丙挽,我...
    開(kāi)封第一講書(shū)人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤肺孵,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后颜阐,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體平窘,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年凳怨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瑰艘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡肤舞,死狀恐怖紫新,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情李剖,我是刑警寧澤芒率,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站篙顺,受9級(jí)特大地震影響偶芍,放射性物質(zhì)發(fā)生泄漏充择。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一匪蟀、第九天 我趴在偏房一處隱蔽的房頂上張望椎麦。 院中可真熱鬧,春花似錦材彪、人聲如沸观挎。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)键兜。三九已至,卻和暖如春穗泵,著一層夾襖步出監(jiān)牢的瞬間普气,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工佃延, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留现诀,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓履肃,卻偏偏與公主長(zhǎng)得像仔沿,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子尺棋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容