1
1
/*
2
- * Copyright 2002-2016 the original author or authors.
2
+ * Copyright 2002-2018 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
17
17
package org .springframework .beans .factory .annotation ;
18
18
19
19
import java .lang .reflect .Method ;
20
+ import java .util .LinkedHashMap ;
21
+ import java .util .Map ;
20
22
import java .util .function .Predicate ;
21
23
22
24
import org .springframework .beans .BeansException ;
23
25
import org .springframework .beans .factory .BeanFactory ;
24
26
import org .springframework .beans .factory .BeanFactoryUtils ;
27
+ import org .springframework .beans .factory .ListableBeanFactory ;
25
28
import org .springframework .beans .factory .NoSuchBeanDefinitionException ;
26
29
import org .springframework .beans .factory .NoUniqueBeanDefinitionException ;
27
30
import org .springframework .beans .factory .config .BeanDefinition ;
28
31
import org .springframework .beans .factory .config .ConfigurableBeanFactory ;
29
- import org .springframework .beans .factory .config .ConfigurableListableBeanFactory ;
30
32
import org .springframework .beans .factory .support .AbstractBeanDefinition ;
31
33
import org .springframework .beans .factory .support .AutowireCandidateQualifier ;
32
34
import org .springframework .beans .factory .support .RootBeanDefinition ;
35
37
import org .springframework .util .Assert ;
36
38
37
39
/**
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.
40
42
*
41
43
* @author Juergen Hoeller
42
44
* @author Chris Beams
45
47
*/
46
48
public abstract class BeanFactoryAnnotationUtils {
47
49
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
+
48
75
/**
49
76
* Obtain a bean of type {@code T} from the given {@code BeanFactory} declaring a
50
77
* qualifier (e.g. via {@code <qualifier>} or {@code @Qualifier}) matching the given
51
78
* 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)
53
80
* @param beanType the type of bean to retrieve
54
81
* @param qualifier the qualifier for selecting between multiple bean matches
55
82
* @return the matching bean of type {@code T} (never {@code null})
56
83
* @throws NoUniqueBeanDefinitionException if multiple matching beans of type {@code T} found
57
84
* @throws NoSuchBeanDefinitionException if no matching bean of type {@code T} found
58
85
* @throws BeansException if the bean could not be created
59
- * @see BeanFactory#getBean( Class)
86
+ * @see BeanFactoryUtils#beanOfTypeIncludingAncestors(ListableBeanFactory, Class)
60
87
*/
61
88
public static <T > T qualifiedBeanOfType (BeanFactory beanFactory , Class <T > beanType , String qualifier )
62
89
throws BeansException {
63
90
64
91
Assert .notNull (beanFactory , "BeanFactory must not be null" );
65
92
66
- if (beanFactory instanceof ConfigurableListableBeanFactory ) {
93
+ if (beanFactory instanceof ListableBeanFactory ) {
67
94
// Full qualifier matching supported.
68
- return qualifiedBeanOfType ((ConfigurableListableBeanFactory ) beanFactory , beanType , qualifier );
95
+ return qualifiedBeanOfType ((ListableBeanFactory ) beanFactory , beanType , qualifier );
69
96
}
70
97
else if (beanFactory .containsBean (qualifier )) {
71
98
// Fallback: target bean at least found by bean name.
@@ -82,12 +109,12 @@ else if (beanFactory.containsBean(qualifier)) {
82
109
/**
83
110
* Obtain a bean of type {@code T} from the given {@code BeanFactory} declaring a qualifier
84
111
* (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
86
113
* @param beanType the type of bean to retrieve
87
114
* @param qualifier the qualifier for selecting between multiple bean matches
88
115
* @return the matching bean of type {@code T} (never {@code null})
89
116
*/
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 ) {
91
118
String [] candidateBeans = BeanFactoryUtils .beanNamesForTypeIncludingAncestors (bf , beanType );
92
119
String matchingBean = null ;
93
120
for (String beanName : candidateBeans ) {
@@ -115,14 +142,14 @@ else if (bf.containsBean(qualifier)) {
115
142
* Check whether the named bean declares a qualifier of the given name.
116
143
* @param qualifier the qualifier to match
117
144
* @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
119
146
* @return {@code true} if either the bean definition (in the XML case)
120
147
* or the bean's factory method (in the {@code @Bean} case) defines a matching
121
148
* qualifier value (through {@code <qualifier>} or {@code @Qualifier})
122
149
* @since 5.0
123
150
*/
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 ) {
126
153
127
154
// Try quick bean name or alias match first...
128
155
if (qualifier .test (beanName )) {
@@ -135,6 +162,7 @@ public static boolean isQualifierMatch(Predicate<String> qualifier, String beanN
135
162
}
136
163
}
137
164
try {
165
+ Class <?> beanType = beanFactory .getType (beanName );
138
166
if (beanFactory instanceof ConfigurableBeanFactory ) {
139
167
BeanDefinition bd = ((ConfigurableBeanFactory ) beanFactory ).getMergedBeanDefinition (beanName );
140
168
// Explicit qualifier metadata on bean definition? (typically in XML definition)
@@ -160,7 +188,6 @@ public static boolean isQualifierMatch(Predicate<String> qualifier, String beanN
160
188
}
161
189
}
162
190
// Corresponding qualifier on bean implementation class? (for custom user types)
163
- Class <?> beanType = beanFactory .getType (beanName );
164
191
if (beanType != null ) {
165
192
Qualifier targetAnnotation = AnnotationUtils .getAnnotation (beanType , Qualifier .class );
166
193
if (targetAnnotation != null ) {
0 commit comments