11/*
2- * Copyright 2002-2011 the original author or authors.
2+ * Copyright 2002-2012 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
1717package org .springframework .context .annotation ;
1818
1919import java .lang .reflect .Method ;
20- import java .util .ArrayList ;
21- import java .util .List ;
2220
2321import net .sf .cglib .proxy .Callback ;
2422import net .sf .cglib .proxy .CallbackFilter ;
2927
3028import org .apache .commons .logging .Log ;
3129import org .apache .commons .logging .LogFactory ;
30+
3231import org .springframework .aop .scope .ScopedProxyFactoryBean ;
3332import org .springframework .beans .factory .BeanFactory ;
3433import org .springframework .beans .factory .DisposableBean ;
@@ -53,40 +52,40 @@ class ConfigurationClassEnhancer {
5352
5453 private static final Log logger = LogFactory .getLog (ConfigurationClassEnhancer .class );
5554
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 ();
5774
58- private final List <Class <? extends Callback >> callbackTypes = new ArrayList <Class <? extends Callback >>();
5975
60- private final CallbackFilter callbackFilter ;
76+ private final Callback [] callbackInstances ;
6177
6278
6379 /**
6480 * Creates a new {@link ConfigurationClassEnhancer} instance.
6581 */
6682 public ConfigurationClassEnhancer (ConfigurableBeanFactory beanFactory ) {
6783 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 };
9089 }
9190
9291 /**
@@ -134,15 +133,11 @@ public interface EnhancedConfiguration extends DisposableBean {
134133 */
135134 private Enhancer newEnhancer (Class <?> superclass ) {
136135 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 );
141136 enhancer .setSuperclass (superclass );
142137 enhancer .setInterfaces (new Class [] {EnhancedConfiguration .class });
143138 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 );
146141 return enhancer ;
147142 }
148143
@@ -153,7 +148,7 @@ private Enhancer newEnhancer(Class<?> superclass) {
153148 private Class <?> createClass (Enhancer enhancer ) {
154149 Class <?> subclass = enhancer .createClass ();
155150 // 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 );
157152 return subclass ;
158153 }
159154
@@ -165,7 +160,7 @@ private Class<?> createClass(Enhancer enhancer) {
165160 * @see BeanMethodInterceptor#enhanceFactoryBean(Class, String)
166161 */
167162 private static class GetObjectMethodInterceptor implements MethodInterceptor {
168-
163+
169164 private final ConfigurableBeanFactory beanFactory ;
170165 private final String beanName ;
171166
@@ -177,7 +172,7 @@ public GetObjectMethodInterceptor(ConfigurableBeanFactory beanFactory, String be
177172 public Object intercept (Object obj , Method method , Object [] args , MethodProxy proxy ) throws Throwable {
178173 return beanFactory .getBean (beanName );
179174 }
180-
175+
181176 }
182177
183178
@@ -215,8 +210,19 @@ public static boolean isDestroyMethod(Method candidateMethod) {
215210 */
216211 private static class BeanMethodInterceptor implements MethodInterceptor {
217212
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+
218223 private final ConfigurableBeanFactory beanFactory ;
219224
225+
220226 public BeanMethodInterceptor (ConfigurableBeanFactory beanFactory ) {
221227 this .beanFactory = beanFactory ;
222228 }
@@ -245,7 +251,7 @@ public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object
245251
246252 // to handle the case of an inter-bean method reference, we must explicitly check the
247253 // container for already cached instances
248-
254+
249255 // first, check to see if the requested bean is a FactoryBean. If so, create a subclass
250256 // proxy that intercepts calls to getObject() and returns any cached bean instance.
251257 // this ensures that the semantics of calling a FactoryBean from within @Bean methods
@@ -327,26 +333,18 @@ private boolean factoryContainsBean(String beanName) {
327333 */
328334 private Object enhanceFactoryBean (Class <?> fbClass , String beanName ) throws InstantiationException , IllegalAccessException {
329335 Enhancer enhancer = new Enhancer ();
330- enhancer .setUseCache (false );
331336 enhancer .setSuperclass (fbClass );
332337 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 );
348346 Class <?> fbSubclass = enhancer .createClass ();
349- Enhancer .registerCallbacks (fbSubclass , callbackInstances . toArray ( new Callback [ callbackInstances . size ()]) );
347+ Enhancer .registerCallbacks (fbSubclass , callbackInstances );
350348 return fbSubclass .newInstance ();
351349 }
352350
0 commit comments