1
1
/*
2
- * Copyright 2012-2016 the original author or authors.
2
+ * Copyright 2012-2017 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.
29
29
30
30
import org .springframework .beans .factory .BeanDefinitionStoreException ;
31
31
import org .springframework .beans .factory .BeanFactory ;
32
- import org .springframework .beans .factory .BeanFactoryUtils ;
33
32
import org .springframework .beans .factory .CannotLoadBeanClassException ;
34
33
import org .springframework .beans .factory .FactoryBean ;
35
34
import org .springframework .beans .factory .ListableBeanFactory ;
43
42
import org .springframework .core .ResolvableType ;
44
43
import org .springframework .core .type .MethodMetadata ;
45
44
import org .springframework .core .type .StandardMethodMetadata ;
45
+ import org .springframework .util .Assert ;
46
46
import org .springframework .util .ClassUtils ;
47
47
import org .springframework .util .ReflectionUtils ;
48
48
import org .springframework .util .StringUtils ;
49
49
50
50
/**
51
- * A registry of the bean types that are contained in a {@link ListableBeanFactory}.
52
- * Provides similar functionality to
51
+ * A registry of the bean types that are contained in a
52
+ * {@link DefaultListableBeanFactory}. Provides similar functionality to
53
53
* {@link ListableBeanFactory#getBeanNamesForType(Class, boolean, boolean)} but is
54
54
* optimized for use by {@link OnBeanCondition} based on the following assumptions:
55
55
* <ul>
62
62
* @author Andy Wilkinson
63
63
* @since 1.2.0
64
64
*/
65
- abstract class BeanTypeRegistry {
65
+ final class BeanTypeRegistry implements SmartInitializingSingleton {
66
66
67
67
private static final Log logger = LogFactory .getLog (BeanTypeRegistry .class );
68
68
69
69
static final String FACTORY_BEAN_OBJECT_TYPE = "factoryBeanObjectType" ;
70
70
71
+ private static final String BEAN_NAME = BeanTypeRegistry .class .getName ();
72
+
73
+ private final DefaultListableBeanFactory beanFactory ;
74
+
75
+ private final Map <String , Class <?>> beanTypes = new HashMap <String , Class <?>>();
76
+
77
+ private int lastBeanDefinitionCount = 0 ;
78
+
79
+ private BeanTypeRegistry (DefaultListableBeanFactory beanFactory ) {
80
+ this .beanFactory = beanFactory ;
81
+ }
82
+
83
+ /**
84
+ * Factory method to get the {@link BeanTypeRegistry} for a given {@link BeanFactory}.
85
+ * @param beanFactory the source bean factory
86
+ * @return the {@link BeanTypeRegistry} for the given bean factory
87
+ */
88
+ public static BeanTypeRegistry create (ListableBeanFactory beanFactory ) {
89
+ Assert .isInstanceOf (DefaultListableBeanFactory .class , beanFactory );
90
+ DefaultListableBeanFactory listableBeanFactory = (DefaultListableBeanFactory ) beanFactory ;
91
+ Assert .isTrue (listableBeanFactory .isAllowEagerClassLoading (),
92
+ "Bean factory must allow eager class loading" );
93
+ if (!listableBeanFactory .containsLocalBean (BEAN_NAME )) {
94
+ BeanDefinition bd = new RootBeanDefinition (BeanTypeRegistry .class );
95
+ bd .getConstructorArgumentValues ().addIndexedArgumentValue (0 , beanFactory );
96
+ listableBeanFactory .registerBeanDefinition (BEAN_NAME , bd );
97
+
98
+ }
99
+ return listableBeanFactory .getBean (BEAN_NAME , BeanTypeRegistry .class );
100
+ }
101
+
71
102
/**
72
103
* Return the names of beans matching the given type (including subclasses), judging
73
104
* from either bean definitions or the value of {@code getObjectType} in the case of
@@ -76,7 +107,81 @@ abstract class BeanTypeRegistry {
76
107
* @return the names of beans (or objects created by FactoryBeans) matching the given
77
108
* object type (including subclasses), or an empty set if none
78
109
*/
79
- public abstract Set <String > getNamesForType (Class <?> type );
110
+ Set <String > getNamesForType (Class <?> type ) {
111
+ if (this .lastBeanDefinitionCount != this .beanFactory .getBeanDefinitionCount ()) {
112
+ Iterator <String > names = this .beanFactory .getBeanNamesIterator ();
113
+ while (names .hasNext ()) {
114
+ String name = names .next ();
115
+ if (!this .beanTypes .containsKey (name )) {
116
+ addBeanType (name );
117
+ }
118
+ }
119
+ this .lastBeanDefinitionCount = this .beanFactory .getBeanDefinitionCount ();
120
+ }
121
+ Set <String > matches = new LinkedHashSet <String >();
122
+ for (Map .Entry <String , Class <?>> entry : this .beanTypes .entrySet ()) {
123
+ if (entry .getValue () != null && type .isAssignableFrom (entry .getValue ())) {
124
+ matches .add (entry .getKey ());
125
+ }
126
+ }
127
+ return matches ;
128
+ }
129
+
130
+ @ Override
131
+ public void afterSingletonsInstantiated () {
132
+ // We're done at this point, free up some memory
133
+ this .beanTypes .clear ();
134
+ this .lastBeanDefinitionCount = 0 ;
135
+ }
136
+
137
+ private void addBeanType (String name ) {
138
+ if (this .beanFactory .containsSingleton (name )) {
139
+ this .beanTypes .put (name , this .beanFactory .getType (name ));
140
+ }
141
+ else if (!this .beanFactory .isAlias (name )) {
142
+ addBeanTypeForNonAliasDefinition (name );
143
+ }
144
+ }
145
+
146
+ private void addBeanTypeForNonAliasDefinition (String name ) {
147
+ try {
148
+ String factoryName = BeanFactory .FACTORY_BEAN_PREFIX + name ;
149
+ RootBeanDefinition beanDefinition = (RootBeanDefinition ) this .beanFactory
150
+ .getMergedBeanDefinition (name );
151
+ if (!beanDefinition .isAbstract ()
152
+ && !requiresEagerInit (beanDefinition .getFactoryBeanName ())) {
153
+ if (this .beanFactory .isFactoryBean (factoryName )) {
154
+ Class <?> factoryBeanGeneric = getFactoryBeanGeneric (this .beanFactory ,
155
+ beanDefinition , name );
156
+ this .beanTypes .put (name , factoryBeanGeneric );
157
+ this .beanTypes .put (factoryName ,
158
+ this .beanFactory .getType (factoryName ));
159
+ }
160
+ else {
161
+ this .beanTypes .put (name , this .beanFactory .getType (name ));
162
+ }
163
+ }
164
+ }
165
+ catch (CannotLoadBeanClassException ex ) {
166
+ // Probably contains a placeholder
167
+ logIgnoredError ("bean class loading failure for bean" , name , ex );
168
+ }
169
+ catch (BeanDefinitionStoreException ex ) {
170
+ // Probably contains a placeholder
171
+ logIgnoredError ("unresolvable metadata in bean definition" , name , ex );
172
+ }
173
+ }
174
+
175
+ private void logIgnoredError (String message , String name , Exception ex ) {
176
+ if (BeanTypeRegistry .logger .isDebugEnabled ()) {
177
+ BeanTypeRegistry .logger .debug ("Ignoring " + message + " '" + name + "'" , ex );
178
+ }
179
+ }
180
+
181
+ private boolean requiresEagerInit (String factoryBeanName ) {
182
+ return (factoryBeanName != null && this .beanFactory .isFactoryBean (factoryBeanName )
183
+ && !this .beanFactory .containsSingleton (factoryBeanName ));
184
+ }
80
185
81
186
/**
82
187
* Attempt to guess the type that a {@link FactoryBean} will return based on the
@@ -86,9 +191,8 @@ abstract class BeanTypeRegistry {
86
191
* @param name the name of the bean
87
192
* @return the generic type of the {@link FactoryBean} or {@code null}
88
193
*/
89
- protected final Class <?> getFactoryBeanGeneric (
90
- ConfigurableListableBeanFactory beanFactory , BeanDefinition definition ,
91
- String name ) {
194
+ private Class <?> getFactoryBeanGeneric (ConfigurableListableBeanFactory beanFactory ,
195
+ BeanDefinition definition , String name ) {
92
196
try {
93
197
return doGetFactoryBeanGeneric (beanFactory , definition , name );
94
198
}
@@ -198,177 +302,4 @@ private Class<?> getTypeFromAttribute(Object attribute)
198
302
return null ;
199
303
}
200
304
201
- /**
202
- * Factory method to get the {@link BeanTypeRegistry} for a given {@link BeanFactory}.
203
- * @param beanFactory the source bean factory
204
- * @return the {@link BeanTypeRegistry} for the given bean factory
205
- */
206
- public static BeanTypeRegistry get (ListableBeanFactory beanFactory ) {
207
- if (beanFactory instanceof DefaultListableBeanFactory ) {
208
- DefaultListableBeanFactory listableBeanFactory = (DefaultListableBeanFactory ) beanFactory ;
209
- if (listableBeanFactory .isAllowEagerClassLoading ()) {
210
- return OptimizedBeanTypeRegistry .getFromFactory (listableBeanFactory );
211
- }
212
- }
213
- return new DefaultBeanTypeRegistry (beanFactory );
214
- }
215
-
216
- /**
217
- * Default (non-optimized) {@link BeanTypeRegistry} implementation.
218
- */
219
- static class DefaultBeanTypeRegistry extends BeanTypeRegistry {
220
-
221
- private final ListableBeanFactory beanFactory ;
222
-
223
- DefaultBeanTypeRegistry (ListableBeanFactory beanFactory ) {
224
- this .beanFactory = beanFactory ;
225
- }
226
-
227
- @ Override
228
- public Set <String > getNamesForType (Class <?> type ) {
229
- Set <String > result = new LinkedHashSet <String >();
230
- result .addAll (Arrays
231
- .asList (this .beanFactory .getBeanNamesForType (type , true , false )));
232
- if (this .beanFactory instanceof ConfigurableListableBeanFactory ) {
233
- collectBeanNamesForTypeFromFactoryBeans (result ,
234
- (ConfigurableListableBeanFactory ) this .beanFactory , type );
235
- }
236
- return result ;
237
- }
238
-
239
- private void collectBeanNamesForTypeFromFactoryBeans (Set <String > result ,
240
- ConfigurableListableBeanFactory beanFactory , Class <?> type ) {
241
- String [] names = beanFactory .getBeanNamesForType (FactoryBean .class , true ,
242
- false );
243
- for (String name : names ) {
244
- name = BeanFactoryUtils .transformedBeanName (name );
245
- BeanDefinition beanDefinition = beanFactory .getBeanDefinition (name );
246
- Class <?> generic = getFactoryBeanGeneric (beanFactory , beanDefinition ,
247
- name );
248
- if (generic != null && ClassUtils .isAssignable (type , generic )) {
249
- result .add (name );
250
- }
251
- }
252
- }
253
-
254
- }
255
-
256
- /**
257
- * {@link BeanTypeRegistry} optimized for {@link DefaultListableBeanFactory}
258
- * implementations that allow eager class loading.
259
- */
260
- static class OptimizedBeanTypeRegistry extends BeanTypeRegistry
261
- implements SmartInitializingSingleton {
262
-
263
- private static final String BEAN_NAME = BeanTypeRegistry .class .getName ();
264
-
265
- private final DefaultListableBeanFactory beanFactory ;
266
-
267
- private final Map <String , Class <?>> beanTypes = new HashMap <String , Class <?>>();
268
-
269
- private int lastBeanDefinitionCount = 0 ;
270
-
271
- OptimizedBeanTypeRegistry (DefaultListableBeanFactory beanFactory ) {
272
- this .beanFactory = beanFactory ;
273
- }
274
-
275
- @ Override
276
- public void afterSingletonsInstantiated () {
277
- // We're done at this point, free up some memory
278
- this .beanTypes .clear ();
279
- this .lastBeanDefinitionCount = 0 ;
280
- }
281
-
282
- @ Override
283
- public Set <String > getNamesForType (Class <?> type ) {
284
- if (this .lastBeanDefinitionCount != this .beanFactory
285
- .getBeanDefinitionCount ()) {
286
- Iterator <String > names = this .beanFactory .getBeanNamesIterator ();
287
- while (names .hasNext ()) {
288
- String name = names .next ();
289
- if (!this .beanTypes .containsKey (name )) {
290
- addBeanType (name );
291
- }
292
- }
293
- this .lastBeanDefinitionCount = this .beanFactory .getBeanDefinitionCount ();
294
- }
295
- Set <String > matches = new LinkedHashSet <String >();
296
- for (Map .Entry <String , Class <?>> entry : this .beanTypes .entrySet ()) {
297
- if (entry .getValue () != null && type .isAssignableFrom (entry .getValue ())) {
298
- matches .add (entry .getKey ());
299
- }
300
- }
301
- return matches ;
302
- }
303
-
304
- private void addBeanType (String name ) {
305
- if (this .beanFactory .containsSingleton (name )) {
306
- this .beanTypes .put (name , this .beanFactory .getType (name ));
307
- }
308
- else if (!this .beanFactory .isAlias (name )) {
309
- addBeanTypeForNonAliasDefinition (name );
310
- }
311
- }
312
-
313
- private void addBeanTypeForNonAliasDefinition (String name ) {
314
- try {
315
- String factoryName = BeanFactory .FACTORY_BEAN_PREFIX + name ;
316
- RootBeanDefinition beanDefinition = (RootBeanDefinition ) this .beanFactory
317
- .getMergedBeanDefinition (name );
318
- if (!beanDefinition .isAbstract ()
319
- && !requiresEagerInit (beanDefinition .getFactoryBeanName ())) {
320
- if (this .beanFactory .isFactoryBean (factoryName )) {
321
- Class <?> factoryBeanGeneric = getFactoryBeanGeneric (
322
- this .beanFactory , beanDefinition , name );
323
- this .beanTypes .put (name , factoryBeanGeneric );
324
- this .beanTypes .put (factoryName ,
325
- this .beanFactory .getType (factoryName ));
326
- }
327
- else {
328
- this .beanTypes .put (name , this .beanFactory .getType (name ));
329
- }
330
- }
331
- }
332
- catch (CannotLoadBeanClassException ex ) {
333
- // Probably contains a placeholder
334
- logIgnoredError ("bean class loading failure for bean" , name , ex );
335
- }
336
- catch (BeanDefinitionStoreException ex ) {
337
- // Probably contains a placeholder
338
- logIgnoredError ("unresolvable metadata in bean definition" , name , ex );
339
- }
340
- }
341
-
342
- private void logIgnoredError (String message , String name , Exception ex ) {
343
- if (BeanTypeRegistry .logger .isDebugEnabled ()) {
344
- BeanTypeRegistry .logger .debug ("Ignoring " + message + " '" + name + "'" ,
345
- ex );
346
- }
347
- }
348
-
349
- private boolean requiresEagerInit (String factoryBeanName ) {
350
- return (factoryBeanName != null
351
- && this .beanFactory .isFactoryBean (factoryBeanName )
352
- && !this .beanFactory .containsSingleton (factoryBeanName ));
353
- }
354
-
355
- /**
356
- * Returns the {@link OptimizedBeanTypeRegistry} for the given bean factory.
357
- * @param factory the source {@link BeanFactory}
358
- * @return the {@link OptimizedBeanTypeRegistry}
359
- */
360
- public static OptimizedBeanTypeRegistry getFromFactory (
361
- DefaultListableBeanFactory factory ) {
362
- if (!factory .containsLocalBean (BEAN_NAME )) {
363
- BeanDefinition bd = new RootBeanDefinition (
364
- OptimizedBeanTypeRegistry .class );
365
- bd .getConstructorArgumentValues ().addIndexedArgumentValue (0 , factory );
366
- factory .registerBeanDefinition (BEAN_NAME , bd );
367
-
368
- }
369
- return factory .getBean (BEAN_NAME , OptimizedBeanTypeRegistry .class );
370
- }
371
-
372
- }
373
-
374
305
}
0 commit comments