11/*
2- * Copyright 2002-2016 the original author or authors.
2+ * Copyright 2002-2018 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
1717package org .springframework .beans .factory .annotation ;
1818
1919import java .lang .reflect .Method ;
20+ import java .util .LinkedHashMap ;
21+ import java .util .Map ;
2022import java .util .function .Predicate ;
2123
2224import org .springframework .beans .BeansException ;
2325import org .springframework .beans .factory .BeanFactory ;
2426import org .springframework .beans .factory .BeanFactoryUtils ;
27+ import org .springframework .beans .factory .ListableBeanFactory ;
2528import org .springframework .beans .factory .NoSuchBeanDefinitionException ;
2629import org .springframework .beans .factory .NoUniqueBeanDefinitionException ;
2730import org .springframework .beans .factory .config .BeanDefinition ;
2831import org .springframework .beans .factory .config .ConfigurableBeanFactory ;
29- import org .springframework .beans .factory .config .ConfigurableListableBeanFactory ;
3032import org .springframework .beans .factory .support .AbstractBeanDefinition ;
3133import org .springframework .beans .factory .support .AutowireCandidateQualifier ;
3234import org .springframework .beans .factory .support .RootBeanDefinition ;
3537import org .springframework .util .Assert ;
3638
3739/**
38- * Convenience methods performing bean lookups related to annotations, for example
39- * Spring's {@link Qualifier @Qualifier} annotation.
40+ * Convenience methods performing bean lookups related to Spring-specific annotations,
41+ * for example Spring's {@link Qualifier @Qualifier} annotation.
4042 *
4143 * @author Juergen Hoeller
4244 * @author Chris Beams
4547 */
4648public abstract class BeanFactoryAnnotationUtils {
4749
50+ /**
51+ * Retrieve all bean of type {@code T} from the given {@code BeanFactory} declaring a
52+ * qualifier (e.g. via {@code <qualifier>} or {@code @Qualifier}) matching the given
53+ * qualifier, or having a bean name matching the given qualifier.
54+ * @param beanFactory the factory to get the target beans from (also searching ancestors)
55+ * @param beanType the type of beans to retrieve
56+ * @param qualifier the qualifier for selecting among all type matches
57+ * @return the matching beans of type {@code T}
58+ * @throws BeansException if any of the matching beans could not be created
59+ * @since 5.1.1
60+ * @see BeanFactoryUtils#beansOfTypeIncludingAncestors(ListableBeanFactory, Class)
61+ */
62+ public static <T > Map <String , T > qualifiedBeansOfType (
63+ ListableBeanFactory beanFactory , Class <T > beanType , String qualifier ) throws BeansException {
64+
65+ String [] candidateBeans = BeanFactoryUtils .beanNamesForTypeIncludingAncestors (beanFactory , beanType );
66+ Map <String , T > result = new LinkedHashMap <>(4 );
67+ for (String beanName : candidateBeans ) {
68+ if (isQualifierMatch (qualifier ::equals , beanName , beanFactory )) {
69+ result .put (beanName , beanFactory .getBean (beanName , beanType ));
70+ }
71+ }
72+ return result ;
73+ }
74+
4875 /**
4976 * Obtain a bean of type {@code T} from the given {@code BeanFactory} declaring a
5077 * qualifier (e.g. via {@code <qualifier>} or {@code @Qualifier}) matching the given
5178 * qualifier, or having a bean name matching the given qualifier.
52- * @param beanFactory the BeanFactory to get the target bean from
79+ * @param beanFactory the factory to get the target bean from (also searching ancestors)
5380 * @param beanType the type of bean to retrieve
5481 * @param qualifier the qualifier for selecting between multiple bean matches
5582 * @return the matching bean of type {@code T} (never {@code null})
5683 * @throws NoUniqueBeanDefinitionException if multiple matching beans of type {@code T} found
5784 * @throws NoSuchBeanDefinitionException if no matching bean of type {@code T} found
5885 * @throws BeansException if the bean could not be created
59- * @see BeanFactory#getBean( Class)
86+ * @see BeanFactoryUtils#beanOfTypeIncludingAncestors(ListableBeanFactory, Class)
6087 */
6188 public static <T > T qualifiedBeanOfType (BeanFactory beanFactory , Class <T > beanType , String qualifier )
6289 throws BeansException {
6390
6491 Assert .notNull (beanFactory , "BeanFactory must not be null" );
6592
66- if (beanFactory instanceof ConfigurableListableBeanFactory ) {
93+ if (beanFactory instanceof ListableBeanFactory ) {
6794 // Full qualifier matching supported.
68- return qualifiedBeanOfType ((ConfigurableListableBeanFactory ) beanFactory , beanType , qualifier );
95+ return qualifiedBeanOfType ((ListableBeanFactory ) beanFactory , beanType , qualifier );
6996 }
7097 else if (beanFactory .containsBean (qualifier )) {
7198 // Fallback: target bean at least found by bean name.
@@ -82,12 +109,12 @@ else if (beanFactory.containsBean(qualifier)) {
82109 /**
83110 * Obtain a bean of type {@code T} from the given {@code BeanFactory} declaring a qualifier
84111 * (e.g. {@code <qualifier>} or {@code @Qualifier}) matching the given qualifier).
85- * @param bf the BeanFactory to get the target bean from
112+ * @param bf the factory to get the target bean from
86113 * @param beanType the type of bean to retrieve
87114 * @param qualifier the qualifier for selecting between multiple bean matches
88115 * @return the matching bean of type {@code T} (never {@code null})
89116 */
90- private static <T > T qualifiedBeanOfType (ConfigurableListableBeanFactory bf , Class <T > beanType , String qualifier ) {
117+ private static <T > T qualifiedBeanOfType (ListableBeanFactory bf , Class <T > beanType , String qualifier ) {
91118 String [] candidateBeans = BeanFactoryUtils .beanNamesForTypeIncludingAncestors (bf , beanType );
92119 String matchingBean = null ;
93120 for (String beanName : candidateBeans ) {
@@ -115,14 +142,14 @@ else if (bf.containsBean(qualifier)) {
115142 * Check whether the named bean declares a qualifier of the given name.
116143 * @param qualifier the qualifier to match
117144 * @param beanName the name of the candidate bean
118- * @param beanFactory the {@code BeanFactory} from which to retrieve the named bean
145+ * @param beanFactory the factory from which to retrieve the named bean
119146 * @return {@code true} if either the bean definition (in the XML case)
120147 * or the bean's factory method (in the {@code @Bean} case) defines a matching
121148 * qualifier value (through {@code <qualifier>} or {@code @Qualifier})
122149 * @since 5.0
123150 */
124- public static boolean isQualifierMatch (Predicate < String > qualifier , String beanName ,
125- @ Nullable BeanFactory beanFactory ) {
151+ public static boolean isQualifierMatch (
152+ Predicate < String > qualifier , String beanName , @ Nullable BeanFactory beanFactory ) {
126153
127154 // Try quick bean name or alias match first...
128155 if (qualifier .test (beanName )) {
@@ -135,6 +162,7 @@ public static boolean isQualifierMatch(Predicate<String> qualifier, String beanN
135162 }
136163 }
137164 try {
165+ Class <?> beanType = beanFactory .getType (beanName );
138166 if (beanFactory instanceof ConfigurableBeanFactory ) {
139167 BeanDefinition bd = ((ConfigurableBeanFactory ) beanFactory ).getMergedBeanDefinition (beanName );
140168 // Explicit qualifier metadata on bean definition? (typically in XML definition)
@@ -160,7 +188,6 @@ public static boolean isQualifierMatch(Predicate<String> qualifier, String beanN
160188 }
161189 }
162190 // Corresponding qualifier on bean implementation class? (for custom user types)
163- Class <?> beanType = beanFactory .getType (beanName );
164191 if (beanType != null ) {
165192 Qualifier targetAnnotation = AnnotationUtils .getAnnotation (beanType , Qualifier .class );
166193 if (targetAnnotation != null ) {
0 commit comments