Spring 注入 Bean 到 List / Map 中

將注入的Bean 放在List或者Map中:


/*
 * spring會自動將 DemoService 的所有實現(xiàn)類bean注入到list集合
 */
@Autowired
private List<DemoService> demoServices;


/*
  * 通過Map注入贸街,通過 spring bean 的名稱作為key動態(tài)獲取對應(yīng)實例
  */
@Autowired
private Map<String, DemoService> demoServiceMap;

Spring在注入集合類的同時,會將集合泛型類的實例填入集合中,作為集合的初始值予弧。
對于list、set填入的是注入類型Spring管理的實例湖饱,對于map掖蛤,Spring會將service的名字作為key,對象作為value封裝進入Map井厌。

這個過程的源碼在 org.springframework.beans.factory.support.DefaultListableBeanFactorydoResolveDependency 方法中調(diào)用了 resolveMultipleBeans 方法:

  1. 如果是數(shù)組蚓庭,則獲取數(shù)組元素類型,查找匹配該類型的所有bean仅仆,返回一個這些bean的數(shù)組器赞;
  2. 如果該類可賦給Collection,并且是一個接口蝇恶,則獲取集合元素類型拳魁,查找匹配該類型的所有bean,返回一個這些bean的集合撮弧;
  3. 如果該類型是Map(注意是type == Map.class)潘懊,且key是String類型,則獲取Map的value的類型贿衍,查找匹配該類型的所有bean授舟,這是一個key為bean name、value為bean實例的一個Map贸辈,返回這個Map释树。
  4. 其他情況則是我們所熟知的按類型自動裝配過程。

源代碼具體如下(Spring版本是5.0.2):

    @Nullable
    public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
            @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
 
        InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
        try {
            Object shortcut = descriptor.resolveShortcut(this);
            if (shortcut != null) {
                return shortcut;
            }
 
            Class<?> type = descriptor.getDependencyType();
            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()));
            }
 
            Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
            if (multipleBeans != null) {
                return multipleBeans;
            }
 
            Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
            if (matchingBeans.isEmpty()) {
                if (isRequired(descriptor)) {
                    raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
                }
                return null;
            }
 
            String autowiredBeanName;
            Object instanceCandidate;
 
            if (matchingBeans.size() > 1) {
                autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
                if (autowiredBeanName == null) {
                    if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
                        return descriptor.resolveNotUnique(type, 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();
                autowiredBeanName = entry.getKey();
                instanceCandidate = entry.getValue();
            }
 
            if (autowiredBeanNames != null) {
                autowiredBeanNames.add(autowiredBeanName);
            }
            if (instanceCandidate instanceof Class) {
                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);
        }
    }
 
    @Nullable
    private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
            @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {
 
        Class<?> type = descriptor.getDependencyType();
        if (type.isArray()) {
            Class<?> componentType = type.getComponentType();
            ResolvableType resolvableType = descriptor.getResolvableType();
            Class<?> resolvedArrayType = resolvableType.resolve();
            if (resolvedArrayType != null && resolvedArrayType != type) {
                type = resolvedArrayType;
                componentType = resolvableType.getComponentType().resolve();
            }
            if (componentType == null) {
                return null;
            }
            Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
                    new MultiElementDescriptor(descriptor));
            if (matchingBeans.isEmpty()) {
                return null;
            }
            if (autowiredBeanNames != null) {
                autowiredBeanNames.addAll(matchingBeans.keySet());
            }
            TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
            Object result = converter.convertIfNecessary(matchingBeans.values(), type);
            if (getDependencyComparator() != null && result instanceof Object[]) {
                Arrays.sort((Object[]) result, adaptDependencyComparator(matchingBeans));
            }
            return result;
        }
        else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
            Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
            if (elementType == null) {
                return null;
            }
            Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
                    new MultiElementDescriptor(descriptor));
            if (matchingBeans.isEmpty()) {
                return null;
            }
            if (autowiredBeanNames != null) {
                autowiredBeanNames.addAll(matchingBeans.keySet());
            }
            TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
            Object result = converter.convertIfNecessary(matchingBeans.values(), type);
            if (getDependencyComparator() != null && result instanceof List) {
                Collections.sort((List<?>) result, adaptDependencyComparator(matchingBeans));
            }
            return result;
        }
        else if (Map.class == type) {
            ResolvableType mapType = descriptor.getResolvableType().asMap();
            Class<?> keyType = mapType.resolveGeneric(0);
            if (String.class != keyType) {
                return null;
            }
            Class<?> valueType = mapType.resolveGeneric(1);
            if (valueType == null) {
                return null;
            }
            Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
                    new MultiElementDescriptor(descriptor));
            if (matchingBeans.isEmpty()) {
                return null;
            }
            if (autowiredBeanNames != null) {
                autowiredBeanNames.addAll(matchingBeans.keySet());
            }
            return matchingBeans;
        }
        else {
            return null;
        }
    }

Kotlin 開發(fā)者社區(qū)

國內(nèi)第一Kotlin 開發(fā)者社區(qū)公眾號,主要分享奢啥、交流 Kotlin 編程語言秸仙、Spring Boot、Android桩盲、React.js/Node.js寂纪、函數(shù)式編程、編程思想等相關(guān)主題赌结。

越是喧囂的世界捞蛋,越需要寧靜的思考。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末柬姚,一起剝皮案震驚了整個濱河市拟杉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌量承,老刑警劉巖搬设,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異宴合,居然都是意外死亡焕梅,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進店門卦洽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人斜棚,你說我怎么就攤上這事阀蒂。” “怎么了弟蚀?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵蚤霞,是天一觀的道長。 經(jīng)常有香客問我义钉,道長昧绣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任捶闸,我火速辦了婚禮夜畴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘删壮。我一直安慰自己贪绘,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布央碟。 她就那樣靜靜地躺著税灌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上菱涤,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天苞也,我揣著相機與錄音,去河邊找鬼粘秆。 笑死如迟,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的翻擒。 我是一名探鬼主播氓涣,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼陋气!你這毒婦竟也來了劳吠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤巩趁,失蹤者是張志新(化名)和其女友劉穎痒玩,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體议慰,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡蠢古,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了别凹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片草讶。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖炉菲,靈堂內(nèi)的尸體忽然破棺而出堕战,到底是詐尸還是另有隱情,我是刑警寧澤拍霜,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布嘱丢,位于F島的核電站,受9級特大地震影響祠饺,放射性物質(zhì)發(fā)生泄漏越驻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一道偷、第九天 我趴在偏房一處隱蔽的房頂上張望缀旁。 院中可真熱鬧,春花似錦试疙、人聲如沸诵棵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽履澳。三九已至嘶窄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間距贷,已是汗流浹背柄冲。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留忠蝗,地道東北人现横。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像阁最,于是被迫代替她去往敵國和親戒祠。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,960評論 2 355