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