17
17
package org .springframework .context .annotation ;
18
18
19
19
import java .lang .reflect .Method ;
20
- import java .util .ArrayList ;
21
- import java .util .List ;
22
20
23
21
import org .apache .commons .logging .Log ;
24
22
import org .apache .commons .logging .LogFactory ;
@@ -54,40 +52,40 @@ class ConfigurationClassEnhancer {
54
52
55
53
private static final Log logger = LogFactory .getLog (ConfigurationClassEnhancer .class );
56
54
57
- private final List <Callback > callbackInstances = new ArrayList <Callback >();
55
+ private static final Class <?>[] CALLBACK_TYPES = { BeanMethodInterceptor .class ,
56
+ DisposableBeanMethodInterceptor .class , NoOp .class };
58
57
59
- private final List < Class <? extends Callback >> callbackTypes = new ArrayList < Class <? extends Callback >>();
58
+ private static final CallbackFilter CALLBACK_FILTER = new CallbackFilter () {
60
59
61
- private final CallbackFilter callbackFilter ;
60
+ public int accept (Method candidateMethod ) {
61
+ // Set up the callback filter to return the index of the BeanMethodInterceptor when
62
+ // handling a @Bean-annotated method; otherwise, return index of the NoOp callback.
63
+ if (BeanAnnotationHelper .isBeanAnnotated (candidateMethod )) {
64
+ return 0 ;
65
+ }
66
+ if (DisposableBeanMethodInterceptor .isDestroyMethod (candidateMethod )) {
67
+ return 1 ;
68
+ }
69
+ return 2 ;
70
+ }
71
+ };
72
+
73
+ private static final Callback DISPOSABLE_BEAN_METHOD_INTERCEPTOR = new DisposableBeanMethodInterceptor ();
74
+
75
+
76
+ private final Callback [] callbackInstances ;
62
77
63
78
64
79
/**
65
80
* Creates a new {@link ConfigurationClassEnhancer} instance.
66
81
*/
67
82
public ConfigurationClassEnhancer (ConfigurableBeanFactory beanFactory ) {
68
83
Assert .notNull (beanFactory , "BeanFactory must not be null" );
69
-
70
- this .callbackInstances .add (new BeanMethodInterceptor (beanFactory ));
71
- this .callbackInstances .add (new DisposableBeanMethodInterceptor ());
72
- this .callbackInstances .add (NoOp .INSTANCE );
73
-
74
- for (Callback callback : this .callbackInstances ) {
75
- this .callbackTypes .add (callback .getClass ());
76
- }
77
-
78
- // Set up the callback filter to return the index of the BeanMethodInterceptor when
79
- // handling a @Bean-annotated method; otherwise, return index of the NoOp callback.
80
- callbackFilter = new CallbackFilter () {
81
- public int accept (Method candidateMethod ) {
82
- if (BeanAnnotationHelper .isBeanAnnotated (candidateMethod )) {
83
- return 0 ;
84
- }
85
- if (DisposableBeanMethodInterceptor .isDestroyMethod (candidateMethod )) {
86
- return 1 ;
87
- }
88
- return 2 ;
89
- }
90
- };
84
+ // Callback instances must be ordered in the same way as CALLBACK_TYPES and CALLBACK_FILTER
85
+ this .callbackInstances = new Callback [] {
86
+ new BeanMethodInterceptor (beanFactory ),
87
+ DISPOSABLE_BEAN_METHOD_INTERCEPTOR ,
88
+ NoOp .INSTANCE };
91
89
}
92
90
93
91
/**
@@ -135,15 +133,11 @@ public interface EnhancedConfiguration extends DisposableBean {
135
133
*/
136
134
private Enhancer newEnhancer (Class <?> superclass ) {
137
135
Enhancer enhancer = new Enhancer ();
138
- // Because callbackFilter and callbackTypes are dynamically populated
139
- // there's no opportunity for caching. This does not appear to be causing
140
- // any performance problem.
141
- enhancer .setUseCache (false );
142
136
enhancer .setSuperclass (superclass );
143
137
enhancer .setInterfaces (new Class [] {EnhancedConfiguration .class });
144
138
enhancer .setUseFactory (false );
145
- enhancer .setCallbackFilter (this . callbackFilter );
146
- enhancer .setCallbackTypes (this . callbackTypes . toArray ( new Class [ this . callbackTypes . size ()]) );
139
+ enhancer .setCallbackFilter (CALLBACK_FILTER );
140
+ enhancer .setCallbackTypes (CALLBACK_TYPES );
147
141
return enhancer ;
148
142
}
149
143
@@ -154,7 +148,7 @@ private Enhancer newEnhancer(Class<?> superclass) {
154
148
private Class <?> createClass (Enhancer enhancer ) {
155
149
Class <?> subclass = enhancer .createClass ();
156
150
// registering callbacks statically (as opposed to threadlocal) is critical for usage in an OSGi env (SPR-5932)
157
- Enhancer .registerStaticCallbacks (subclass , this .callbackInstances . toArray ( new Callback [ this . callbackInstances . size ()]) );
151
+ Enhancer .registerStaticCallbacks (subclass , this .callbackInstances );
158
152
return subclass ;
159
153
}
160
154
@@ -166,7 +160,7 @@ private Class<?> createClass(Enhancer enhancer) {
166
160
* @see BeanMethodInterceptor#enhanceFactoryBean(Class, String)
167
161
*/
168
162
private static class GetObjectMethodInterceptor implements MethodInterceptor {
169
-
163
+
170
164
private final ConfigurableBeanFactory beanFactory ;
171
165
private final String beanName ;
172
166
@@ -178,7 +172,7 @@ public GetObjectMethodInterceptor(ConfigurableBeanFactory beanFactory, String be
178
172
public Object intercept (Object obj , Method method , Object [] args , MethodProxy proxy ) throws Throwable {
179
173
return beanFactory .getBean (beanName );
180
174
}
181
-
175
+
182
176
}
183
177
184
178
@@ -216,8 +210,19 @@ public static boolean isDestroyMethod(Method candidateMethod) {
216
210
*/
217
211
private static class BeanMethodInterceptor implements MethodInterceptor {
218
212
213
+ private static final Class <?>[] CALLBACK_TYPES = {
214
+ GetObjectMethodInterceptor .class , NoOp .class };
215
+
216
+ private static final CallbackFilter CALLBACK_FITLER = new CallbackFilter () {
217
+ public int accept (Method method ) {
218
+ return method .getName ().equals ("getObject" ) ? 0 : 1 ;
219
+ }
220
+ };
221
+
222
+
219
223
private final ConfigurableBeanFactory beanFactory ;
220
224
225
+
221
226
public BeanMethodInterceptor (ConfigurableBeanFactory beanFactory ) {
222
227
this .beanFactory = beanFactory ;
223
228
}
@@ -246,7 +251,7 @@ public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object
246
251
247
252
// to handle the case of an inter-bean method reference, we must explicitly check the
248
253
// container for already cached instances
249
-
254
+
250
255
// first, check to see if the requested bean is a FactoryBean. If so, create a subclass
251
256
// proxy that intercepts calls to getObject() and returns any cached bean instance.
252
257
// this ensures that the semantics of calling a FactoryBean from within @Bean methods
@@ -328,26 +333,18 @@ private boolean factoryContainsBean(String beanName) {
328
333
*/
329
334
private Object enhanceFactoryBean (Class <?> fbClass , String beanName ) throws InstantiationException , IllegalAccessException {
330
335
Enhancer enhancer = new Enhancer ();
331
- enhancer .setUseCache (false );
332
336
enhancer .setSuperclass (fbClass );
333
337
enhancer .setUseFactory (false );
334
- enhancer .setCallbackFilter (new CallbackFilter () {
335
- public int accept (Method method ) {
336
- return method .getName ().equals ("getObject" ) ? 0 : 1 ;
337
- }
338
- });
339
- List <Callback > callbackInstances = new ArrayList <Callback >();
340
- callbackInstances .add (new GetObjectMethodInterceptor (this .beanFactory , beanName ));
341
- callbackInstances .add (NoOp .INSTANCE );
342
-
343
- List <Class <? extends Callback >> callbackTypes = new ArrayList <Class <? extends Callback >>();
344
- for (Callback callback : callbackInstances ) {
345
- callbackTypes .add (callback .getClass ());
346
- }
347
-
348
- enhancer .setCallbackTypes (callbackTypes .toArray (new Class [callbackTypes .size ()]));
338
+ enhancer .setCallbackFilter (CALLBACK_FITLER );
339
+ // Callback instances must be ordered in the same way as CALLBACK_TYPES and CALLBACK_FILTER
340
+ Callback [] callbackInstances = new Callback [] {
341
+ new GetObjectMethodInterceptor (this .beanFactory , beanName ),
342
+ NoOp .INSTANCE
343
+ };
344
+
345
+ enhancer .setCallbackTypes (CALLBACK_TYPES );
349
346
Class <?> fbSubclass = enhancer .createClass ();
350
- Enhancer .registerCallbacks (fbSubclass , callbackInstances . toArray ( new Callback [ callbackInstances . size ()]) );
347
+ Enhancer .registerCallbacks (fbSubclass , callbackInstances );
351
348
return fbSubclass .newInstance ();
352
349
}
353
350
0 commit comments