1717package org .springframework .context .annotation ;
1818
1919import java .lang .reflect .Method ;
20- import java .util .ArrayList ;
21- import java .util .List ;
2220
2321import org .apache .commons .logging .Log ;
2422import org .apache .commons .logging .LogFactory ;
@@ -54,40 +52,40 @@ class ConfigurationClassEnhancer {
5452
5553 private static final Log logger = LogFactory .getLog (ConfigurationClassEnhancer .class );
5654
57- private final List <Callback > callbackInstances = new ArrayList <Callback >();
55+ private static final Class <?>[] CALLBACK_TYPES = { BeanMethodInterceptor .class ,
56+ DisposableBeanMethodInterceptor .class , NoOp .class };
5857
59- private final List < Class <? extends Callback >> callbackTypes = new ArrayList < Class <? extends Callback >>();
58+ private static final CallbackFilter CALLBACK_FILTER = new CallbackFilter () {
6059
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 ;
6277
6378
6479 /**
6580 * Creates a new {@link ConfigurationClassEnhancer} instance.
6681 */
6782 public ConfigurationClassEnhancer (ConfigurableBeanFactory beanFactory ) {
6883 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 };
9189 }
9290
9391 /**
@@ -135,15 +133,11 @@ public interface EnhancedConfiguration extends DisposableBean {
135133 */
136134 private Enhancer newEnhancer (Class <?> superclass ) {
137135 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 );
142136 enhancer .setSuperclass (superclass );
143137 enhancer .setInterfaces (new Class [] {EnhancedConfiguration .class });
144138 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 );
147141 return enhancer ;
148142 }
149143
@@ -154,7 +148,7 @@ private Enhancer newEnhancer(Class<?> superclass) {
154148 private Class <?> createClass (Enhancer enhancer ) {
155149 Class <?> subclass = enhancer .createClass ();
156150 // 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 );
158152 return subclass ;
159153 }
160154
@@ -166,7 +160,7 @@ private Class<?> createClass(Enhancer enhancer) {
166160 * @see BeanMethodInterceptor#enhanceFactoryBean(Class, String)
167161 */
168162 private static class GetObjectMethodInterceptor implements MethodInterceptor {
169-
163+
170164 private final ConfigurableBeanFactory beanFactory ;
171165 private final String beanName ;
172166
@@ -178,7 +172,7 @@ public GetObjectMethodInterceptor(ConfigurableBeanFactory beanFactory, String be
178172 public Object intercept (Object obj , Method method , Object [] args , MethodProxy proxy ) throws Throwable {
179173 return beanFactory .getBean (beanName );
180174 }
181-
175+
182176 }
183177
184178
@@ -216,8 +210,19 @@ public static boolean isDestroyMethod(Method candidateMethod) {
216210 */
217211 private static class BeanMethodInterceptor implements MethodInterceptor {
218212
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+
219223 private final ConfigurableBeanFactory beanFactory ;
220224
225+
221226 public BeanMethodInterceptor (ConfigurableBeanFactory beanFactory ) {
222227 this .beanFactory = beanFactory ;
223228 }
@@ -246,7 +251,7 @@ public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object
246251
247252 // to handle the case of an inter-bean method reference, we must explicitly check the
248253 // container for already cached instances
249-
254+
250255 // first, check to see if the requested bean is a FactoryBean. If so, create a subclass
251256 // proxy that intercepts calls to getObject() and returns any cached bean instance.
252257 // this ensures that the semantics of calling a FactoryBean from within @Bean methods
@@ -328,26 +333,18 @@ private boolean factoryContainsBean(String beanName) {
328333 */
329334 private Object enhanceFactoryBean (Class <?> fbClass , String beanName ) throws InstantiationException , IllegalAccessException {
330335 Enhancer enhancer = new Enhancer ();
331- enhancer .setUseCache (false );
332336 enhancer .setSuperclass (fbClass );
333337 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 );
349346 Class <?> fbSubclass = enhancer .createClass ();
350- Enhancer .registerCallbacks (fbSubclass , callbackInstances . toArray ( new Callback [ callbackInstances . size ()]) );
347+ Enhancer .registerCallbacks (fbSubclass , callbackInstances );
351348 return fbSubclass .newInstance ();
352349 }
353350
0 commit comments