1616
1717package  org .springframework .context .annotation ;
1818
19+ import  java .lang .reflect .Field ;
1920import  java .lang .reflect .Method ;
2021import  java .util .Arrays ;
2122
2223import  org .apache .commons .logging .Log ;
2324import  org .apache .commons .logging .LogFactory ;
24- 
2525import  org .springframework .aop .scope .ScopedProxyFactoryBean ;
26+ import  org .springframework .asm .Type ;
2627import  org .springframework .beans .factory .BeanFactory ;
28+ import  org .springframework .beans .factory .BeanFactoryAware ;
2729import  org .springframework .beans .factory .DisposableBean ;
28- import  org .springframework .beans .factory .FactoryBean ;
2930import  org .springframework .beans .factory .config .BeanFactoryPostProcessor ;
3031import  org .springframework .beans .factory .config .ConfigurableBeanFactory ;
3132import  org .springframework .beans .factory .support .SimpleInstantiationStrategy ;
33+ import  org .springframework .cglib .core .ClassGenerator ;
34+ import  org .springframework .cglib .core .Constants ;
35+ import  org .springframework .cglib .core .DefaultGeneratorStrategy ;
3236import  org .springframework .cglib .proxy .Callback ;
3337import  org .springframework .cglib .proxy .CallbackFilter ;
3438import  org .springframework .cglib .proxy .Enhancer ;
3539import  org .springframework .cglib .proxy .MethodInterceptor ;
3640import  org .springframework .cglib .proxy .MethodProxy ;
3741import  org .springframework .cglib .proxy .NoOp ;
42+ import  org .springframework .cglib .transform .ClassEmitterTransformer ;
43+ import  org .springframework .cglib .transform .TransformingClassGenerator ;
3844import  org .springframework .core .annotation .AnnotationUtils ;
3945import  org .springframework .util .Assert ;
46+ import  org .springframework .util .ReflectionUtils ;
4047
4148/** 
4249 * Enhances {@link Configuration} classes by generating a CGLIB subclass capable of 
@@ -52,25 +59,18 @@ class ConfigurationClassEnhancer {
5259
5360	private  static  final  Log  logger  = LogFactory .getLog (ConfigurationClassEnhancer .class );
5461
55- 	private  static  final  CallbackFilter   CALLBACK_FILTER  = new  ConfigurationClassCallbackFilter (); 
56- 
57- 	private   static   final   Callback   DISPOSABLE_BEAN_METHOD_INTERCEPTOR  =  new  DisposableBeanMethodInterceptor (); 
58- 
59- 	private   static   final   Class <?>[]  CALLBACK_TYPES  = 
60- 			{ BeanMethodInterceptor . class ,  DisposableBeanMethodInterceptor . class ,  NoOp . class };
62+ 	private  static  final  Callback []  CALLBACKS  = new  Callback [] { 
63+ 		 new   BeanMethodInterceptor (), 
64+ 		 new  DisposableBeanMethodInterceptor (), 
65+ 		 new   BeanFactoryAwareMethodInterceptor (), 
66+ 		 NoOp . INSTANCE 
67+ 	};
6168
62- 	private  final  Callback [] callbackInstances ;
69+ 	private  static  final  ConditionalCallbackFilter  CALLBACK_FILTER  =
70+ 			new  ConditionalCallbackFilter (CALLBACKS );
6371
6472
65- 	/** 
66- 	 * Creates a new {@link ConfigurationClassEnhancer} instance. 
67- 	 */ 
68- 	public  ConfigurationClassEnhancer (ConfigurableBeanFactory  beanFactory ) {
69- 		Assert .notNull (beanFactory , "BeanFactory must not be null" );
70- 		// Callback instances must be ordered in the same way as CALLBACK_TYPES and CALLBACK_FILTER 
71- 		this .callbackInstances  = new  Callback []
72- 				{new  BeanMethodInterceptor (beanFactory ), DISPOSABLE_BEAN_METHOD_INTERCEPTOR , NoOp .INSTANCE };
73- 	}
73+ 	private  static  final  String  BEAN_FACTORY_FIELD  = "$$beanFactory" ;
7474
7575	/** 
7676	 * Loads the specified class and generates a CGLIB subclass of it equipped with 
@@ -106,7 +106,21 @@ private Enhancer newEnhancer(Class<?> superclass) {
106106		enhancer .setInterfaces (new  Class [] {EnhancedConfiguration .class });
107107		enhancer .setUseFactory (false );
108108		enhancer .setCallbackFilter (CALLBACK_FILTER );
109- 		enhancer .setCallbackTypes (CALLBACK_TYPES );
109+ 		enhancer .setCallbackTypes (CALLBACK_FILTER .getCallbackTypes ());
110+ 		enhancer .setStrategy (new  DefaultGeneratorStrategy () {
111+ 			@ Override 
112+ 			protected  ClassGenerator  transform (ClassGenerator  cg ) throws  Exception  {
113+ 				ClassEmitterTransformer  transformer  = new  ClassEmitterTransformer () {
114+ 					@ Override 
115+ 					public  void  end_class () {
116+ 						declare_field (Constants .ACC_PUBLIC , BEAN_FACTORY_FIELD ,
117+ 								Type .getType (BeanFactory .class ), null );
118+ 						super .end_class ();
119+ 					}
120+ 				};
121+ 				return  new  TransformingClassGenerator (cg , transformer );
122+ 			}
123+ 		});
110124		return  enhancer ;
111125	}
112126
@@ -117,7 +131,7 @@ private Enhancer newEnhancer(Class<?> superclass) {
117131	private  Class <?> createClass (Enhancer  enhancer ) {
118132		Class <?> subclass  = enhancer .createClass ();
119133		// registering callbacks statically (as opposed to threadlocal) is critical for usage in an OSGi env (SPR-5932) 
120- 		Enhancer .registerStaticCallbacks (subclass , this . callbackInstances );
134+ 		Enhancer .registerStaticCallbacks (subclass , CALLBACKS );
121135		return  subclass ;
122136	}
123137
@@ -128,67 +142,75 @@ private Class<?> createClass(Enhancer enhancer) {
128142	 * Facilitates idempotent behavior for {@link ConfigurationClassEnhancer#enhance(Class)} 
129143	 * through checking to see if candidate classes are already assignable to it, e.g. 
130144	 * have already been enhanced. 
131- 	 * <p>Also extends {@link DisposableBean}, as all enhanced 
132- 	 * {@code @Configuration} classes must de-register static CGLIB callbacks on 
133- 	 * destruction, which is handled by the (private) {@code DisposableBeanMethodInterceptor}. 
145+ 	 * <p>Also extends {@link DisposableBean} and {@link BeanFactoryAware}, as all 
146+ 	 * enhanced {@code @Configuration} classes require access to the {@link BeanFactory} 
147+ 	 * that created them and must de-register static CGLIB callbacks on destruction, 
148+ 	 * which is handled by the (private) {@code DisposableBeanMethodInterceptor}. 
134149	 * <p>Note that this interface is intended for framework-internal use only, however 
135150	 * must remain public in order to allow access to subclasses generated from other 
136151	 * packages (i.e. user code). 
137152	 */ 
138- 	public  interface  EnhancedConfiguration  extends  DisposableBean  {
153+ 	public  interface  EnhancedConfiguration  extends  DisposableBean ,  BeanFactoryAware  {
139154	}
140155
141156
142157	/** 
143- 	 * CGLIB CallbackFilter implementation that points to BeanMethodInterceptor and  
144- 	 * DisposableBeanMethodInterceptor.  
158+ 	 * Conditional {@link Callback}.  
159+ 	 * @see ConditionalCallbackFilter  
145160	 */ 
146- 	private  static  class  ConfigurationClassCallbackFilter  implements  CallbackFilter  {
147- 
148- 		public  int  accept (Method  candidateMethod ) {
149- 			// Set up the callback filter to return the index of the BeanMethodInterceptor when 
150- 			// handling a @Bean-annotated method; otherwise, return index of the NoOp callback. 
151- 			if  (BeanAnnotationHelper .isBeanAnnotated (candidateMethod )) {
152- 				return  0 ;
153- 			}
154- 			if  (DisposableBeanMethodInterceptor .isDestroyMethod (candidateMethod )) {
155- 				return  1 ;
156- 			}
157- 			return  2 ;
158- 		}
161+ 	private  static  interface  ConditionalCallback  extends  Callback  {
162+ 		boolean  isMatch (Method  candidateMethod );
159163	}
160164
161- 
162165	/** 
163- 	 * Intercepts calls to {@link FactoryBean#getObject()}, delegating to calling 
164- 	 * {@link BeanFactory#getBean(String)} in order to respect caching / scoping. 
165- 	 * @see BeanMethodInterceptor#intercept(Object, Method, Object[], MethodProxy) 
166- 	 * @see BeanMethodInterceptor#enhanceFactoryBean(Class, String) 
166+ 	 * A {@link CallbackFilter} that works by interrogating {@link Callback}s in the order 
167+ 	 * that they are defined via {@link ConditionalCallback}. 
167168	 */ 
168- 	private  static  class  GetObjectMethodInterceptor  implements  MethodInterceptor  {
169+ 	private  static  class  ConditionalCallbackFilter  implements  CallbackFilter  {
169170
170- 		private  final  ConfigurableBeanFactory   beanFactory ;
171+ 		private  final  Callback []  callbacks ;
171172
172- 		private  final  String   beanName ;
173+ 		private  final  Class <?>[]  callbackTypes ;
173174
174- 		public  GetObjectMethodInterceptor (ConfigurableBeanFactory  beanFactory , String  beanName ) {
175- 			this .beanFactory  = beanFactory ;
176- 			this .beanName  = beanName ;
175+ 		public  ConditionalCallbackFilter (Callback [] callbacks ) {
176+ 			this .callbacks  = callbacks ;
177+ 			this .callbackTypes  = new  Class <?>[callbacks .length ];
178+ 			for  (int  i  = 0 ; i  < callbacks .length ; i ++) {
179+ 				callbackTypes [i ] = callbacks [i ].getClass ();
180+ 			}
177181		}
178182
179- 		public  Object  intercept (Object  obj , Method  method , Object [] args , MethodProxy  proxy ) throws  Throwable  {
180- 			return  this .beanFactory .getBean (this .beanName );
183+ 		@ Override 
184+ 		public  int  accept (Method  method ) {
185+ 			for  (int  i  = 0 ; i  < callbacks .length ; i ++) {
186+ 				if  (!(callbacks [i ] instanceof  ConditionalCallback ) ||
187+ 						((ConditionalCallback ) callbacks [i ]).isMatch (method )) {
188+ 					return  i ;
189+ 				}
190+ 			}
191+ 			throw  new  IllegalStateException ("No callback available for method " 
192+ 					+ method .getName ());
181193		}
182- 	}
183194
195+ 		public  Class <?>[] getCallbackTypes () {
196+ 			return  callbackTypes ;
197+ 		}
198+ 	}
184199
185200	/** 
186201	 * Intercepts the invocation of any {@link DisposableBean#destroy()} on @Configuration 
187202	 * class instances for the purpose of de-registering CGLIB callbacks. This helps avoid 
188203	 * garbage collection issues. See SPR-7901. 
189204	 * @see EnhancedConfiguration 
190205	 */ 
191- 	private  static  class  DisposableBeanMethodInterceptor  implements  MethodInterceptor  {
206+ 	private  static  class  DisposableBeanMethodInterceptor  implements  MethodInterceptor ,
207+ 			ConditionalCallback  {
208+ 
209+ 		public  boolean  isMatch (Method  candidateMethod ) {
210+ 			return  candidateMethod .getName ().equals ("destroy" )
211+ 					&& candidateMethod .getParameterTypes ().length  == 0 
212+ 					&& DisposableBean .class .isAssignableFrom (candidateMethod .getDeclaringClass ());
213+ 		}
192214
193215		public  Object  intercept (Object  obj , Method  method , Object [] args , MethodProxy  proxy ) throws  Throwable  {
194216			Enhancer .registerStaticCallbacks (obj .getClass (), null );
@@ -200,10 +222,38 @@ public Object intercept(Object obj, Method method, Object[] args, MethodProxy pr
200222			return  null ;
201223		}
202224
203- 		public  static  boolean  isDestroyMethod (Method  candidateMethod ) {
204- 			return  candidateMethod .getName ().equals ("destroy" ) &&
205- 				candidateMethod .getParameterTypes ().length  == 0  &&
206- 				DisposableBean .class .isAssignableFrom (candidateMethod .getDeclaringClass ());
225+ 	}
226+ 
227+ 
228+ 	/** 
229+ 	 * Intercepts the invocation of any 
230+ 	 * {@link BeanFactoryAware#setBeanFactory(BeanFactory)} on {@code @Configuration} 
231+ 	 * class instances for the purpose of recording the {@link BeanFactory}. 
232+ 	 * 
233+ 	 * @see EnhancedConfiguration 
234+ 	 */ 
235+ 	private  static  class  BeanFactoryAwareMethodInterceptor  implements  MethodInterceptor ,
236+ 			ConditionalCallback  {
237+ 
238+ 		public  boolean  isMatch (Method  candidateMethod ) {
239+ 			return  candidateMethod .getName ().equals ("setBeanFactory" )
240+ 					&& candidateMethod .getParameterTypes ().length  == 1 
241+ 					&& candidateMethod .getParameterTypes ()[0 ].equals (BeanFactory .class )
242+ 					&& BeanFactoryAware .class .isAssignableFrom (candidateMethod .getDeclaringClass ());
243+ 		}
244+ 
245+ 		public  Object  intercept (Object  obj , Method  method , Object [] args ,
246+ 				MethodProxy  proxy ) throws  Throwable  {
247+ 			Field  field  = obj .getClass ().getDeclaredField (BEAN_FACTORY_FIELD );
248+ 			Assert .state (field  != null , "Unable to find generated bean factory field" );
249+ 			field .set (obj , args [0 ]);
250+ 
251+ 			// does the actual (non-CGLIB) superclass actually implement BeanFactoryAware? 
252+ 			// if so, call its setBeanFactory() method. If not, just exit. 
253+ 			if  (BeanFactoryAware .class .isAssignableFrom (obj .getClass ().getSuperclass ())) {
254+ 				return  proxy .invokeSuper (obj , args );
255+ 			}
256+ 			return  null ;
207257		}
208258	}
209259
@@ -214,20 +264,10 @@ public static boolean isDestroyMethod(Method candidateMethod) {
214264	 * @see Bean 
215265	 * @see ConfigurationClassEnhancer 
216266	 */ 
217- 	private  static  class  BeanMethodInterceptor  implements  MethodInterceptor  {
218- 
219- 		private  static  final  Class <?>[] CALLBACK_TYPES  = {GetObjectMethodInterceptor .class , NoOp .class };
220- 
221- 		private  static  final  CallbackFilter  CALLBACK_FILTER  = new  CallbackFilter () {
222- 			public  int  accept (Method  method ) {
223- 				return  (method .getName ().equals ("getObject" ) ? 0  : 1 );
224- 			}
225- 		};
226- 
227- 		private  final  ConfigurableBeanFactory  beanFactory ;
267+ 	private  static  class  BeanMethodInterceptor  implements  MethodInterceptor , ConditionalCallback  {
228268
229- 		public  BeanMethodInterceptor ( ConfigurableBeanFactory   beanFactory ) {
230- 			this . beanFactory  =  beanFactory ;
269+ 		public  boolean   isMatch ( Method   candidateMethod ) {
270+ 			return   BeanAnnotationHelper . isBeanAnnotated ( candidateMethod ) ;
231271		}
232272
233273		/** 
@@ -240,13 +280,14 @@ public BeanMethodInterceptor(ConfigurableBeanFactory beanFactory) {
240280		public  Object  intercept (Object  enhancedConfigInstance , Method  beanMethod , Object [] beanMethodArgs ,
241281					MethodProxy  cglibMethodProxy ) throws  Throwable  {
242282
283+ 			ConfigurableBeanFactory  beanFactory  = getBeanFactory (enhancedConfigInstance );
243284			String  beanName  = BeanAnnotationHelper .determineBeanNameFor (beanMethod );
244285
245286			// determine whether this bean is a scoped-proxy 
246287			Scope  scope  = AnnotationUtils .findAnnotation (beanMethod , Scope .class );
247288			if  (scope  != null  && scope .proxyMode () != ScopedProxyMode .NO ) {
248289				String  scopedBeanName  = ScopedProxyCreator .getTargetBeanName (beanName );
249- 				if  (this . beanFactory .isCurrentlyInCreation (scopedBeanName )) {
290+ 				if  (beanFactory .isCurrentlyInCreation (scopedBeanName )) {
250291					beanName  = scopedBeanName ;
251292				}
252293			}
@@ -258,19 +299,20 @@ public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object
258299			// proxy that intercepts calls to getObject() and returns any cached bean instance. 
259300			// this ensures that the semantics of calling a FactoryBean from within @Bean methods 
260301			// is the same as that of referring to a FactoryBean within XML. See SPR-6602. 
261- 			if  (factoryContainsBean (BeanFactory .FACTORY_BEAN_PREFIX  + beanName ) && factoryContainsBean (beanName )) {
262- 				Object  factoryBean  = this .beanFactory .getBean (BeanFactory .FACTORY_BEAN_PREFIX  + beanName );
302+ 			if  (factoryContainsBean (beanFactory , BeanFactory .FACTORY_BEAN_PREFIX  + beanName ) &&
303+ 					factoryContainsBean (beanFactory , beanName )) {
304+ 				Object  factoryBean  = beanFactory .getBean (BeanFactory .FACTORY_BEAN_PREFIX  + beanName );
263305				if  (factoryBean  instanceof  ScopedProxyFactoryBean ) {
264306					// pass through - scoped proxy factory beans are a special case and should not 
265307					// be further proxied 
266308				}
267309				else  {
268310					// it is a candidate FactoryBean - go ahead with enhancement 
269- 					return  enhanceFactoryBean (factoryBean .getClass (), beanName );
311+ 					return  enhanceFactoryBean (factoryBean .getClass (), beanFactory ,  beanName );
270312				}
271313			}
272314
273- 			if  (isCurrentlyInvokedFactoryMethod (beanMethod ) && !this . beanFactory .containsSingleton (beanName )) {
315+ 			if  (isCurrentlyInvokedFactoryMethod (beanMethod ) && !beanFactory .containsSingleton (beanName )) {
274316				// the factory is calling the bean method in order to instantiate and register the bean 
275317				// (i.e. via a getBean() call) -> invoke the super implementation of the method to actually 
276318				// create the bean instance. 
@@ -290,20 +332,19 @@ public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object
290332				// call to the bean method, direct or indirect. The bean may have already been 
291333				// marked as 'in creation' in certain autowiring scenarios; if so, temporarily 
292334				// set the in-creation status to false in order to avoid an exception. 
293- 				boolean  alreadyInCreation  = this . beanFactory .isCurrentlyInCreation (beanName );
335+ 				boolean  alreadyInCreation  = beanFactory .isCurrentlyInCreation (beanName );
294336				try  {
295337					if  (alreadyInCreation ) {
296- 						this . beanFactory .setCurrentlyInCreation (beanName , false );
338+ 						beanFactory .setCurrentlyInCreation (beanName , false );
297339					}
298- 					return  this . beanFactory .getBean (beanName );
340+ 					return  beanFactory .getBean (beanName );
299341				}
300342				finally  {
301343					if  (alreadyInCreation ) {
302- 						this . beanFactory .setCurrentlyInCreation (beanName , true );
344+ 						beanFactory .setCurrentlyInCreation (beanName , true );
303345					}
304346				}
305347			}
306- 
307348		}
308349
309350		/** 
@@ -319,8 +360,8 @@ public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object
319360		 * @param beanName name of bean to check for 
320361		 * @return whether <var>beanName</var> already exists in the factory 
321362		 */ 
322- 		private  boolean  factoryContainsBean (String  beanName ) {
323- 			return  (this . beanFactory .containsBean (beanName ) && !this . beanFactory .isCurrentlyInCreation (beanName ));
363+ 		private  boolean  factoryContainsBean (ConfigurableBeanFactory   beanFactory ,  String  beanName ) {
364+ 			return  (beanFactory .containsBean (beanName ) && !beanFactory .isCurrentlyInCreation (beanName ));
324365		}
325366
326367		/** 
@@ -342,20 +383,29 @@ private boolean isCurrentlyInvokedFactoryMethod(Method method) {
342383		 * instance directly. If a FactoryBean instance is fetched through the container via &-dereferencing, 
343384		 * it will not be proxied. This too is aligned with the way XML configuration works. 
344385		 */ 
345- 		private  Object  enhanceFactoryBean (Class <?> fbClass , String  beanName ) throws  InstantiationException , IllegalAccessException  {
386+ 		private  Object  enhanceFactoryBean (Class <?> fbClass , final  ConfigurableBeanFactory  beanFactory ,
387+ 				final  String  beanName ) throws  InstantiationException , IllegalAccessException  {
346388			Enhancer  enhancer  = new  Enhancer ();
347389			enhancer .setSuperclass (fbClass );
348390			enhancer .setUseFactory (false );
349- 			enhancer .setCallbackFilter (CALLBACK_FILTER );
350- 			// Callback instances must be ordered in the same way as CALLBACK_TYPES and CALLBACK_FILTER 
351- 			Callback [] callbackInstances  = new  Callback [] {
352- 					new  GetObjectMethodInterceptor (this .beanFactory , beanName ),
353- 					NoOp .INSTANCE 
354- 			};
355- 			enhancer .setCallbackTypes (CALLBACK_TYPES );
356- 			Class <?> fbSubclass  = enhancer .createClass ();
357- 			Enhancer .registerCallbacks (fbSubclass , callbackInstances );
358- 			return  fbSubclass .newInstance ();
391+ 			enhancer .setCallback (new  MethodInterceptor () {
392+ 				public  Object  intercept (Object  obj , Method  method , Object [] args ,
393+ 						MethodProxy  proxy ) throws  Throwable  {
394+ 					if  (method .getName ().equals ("getObject" ) && args .length  == 0 ) {
395+ 						return  beanFactory .getBean (beanName );
396+ 					}
397+ 					return  proxy .invokeSuper (obj , args );
398+ 				}
399+ 			});
400+ 			return  enhancer .create ();
401+ 		}
402+ 
403+ 		private  ConfigurableBeanFactory  getBeanFactory (Object  enhancedConfigInstance ) {
404+ 			Field  field  = ReflectionUtils .findField (enhancedConfigInstance .getClass (), BEAN_FACTORY_FIELD );
405+ 			Assert .state (field  != null , "Unable to find generated bean factory field" );
406+ 			Object  beanFactory  = ReflectionUtils .getField (field , enhancedConfigInstance );
407+ 			Assert .isInstanceOf (ConfigurableBeanFactory .class , beanFactory );
408+ 			return  (ConfigurableBeanFactory ) beanFactory ;
359409		}
360410	}
361411
0 commit comments