|
|
@ -17,8 +17,6 @@ |
|
|
|
package org.springframework.context.annotation; |
|
|
|
package org.springframework.context.annotation; |
|
|
|
|
|
|
|
|
|
|
|
import java.lang.reflect.Method; |
|
|
|
import java.lang.reflect.Method; |
|
|
|
import java.util.ArrayList; |
|
|
|
|
|
|
|
import java.util.List; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import org.apache.commons.logging.Log; |
|
|
|
import org.apache.commons.logging.Log; |
|
|
|
import org.apache.commons.logging.LogFactory; |
|
|
|
import org.apache.commons.logging.LogFactory; |
|
|
@ -54,11 +52,28 @@ class ConfigurationClassEnhancer { |
|
|
|
|
|
|
|
|
|
|
|
private static final Log logger = LogFactory.getLog(ConfigurationClassEnhancer.class); |
|
|
|
private static final Log logger = LogFactory.getLog(ConfigurationClassEnhancer.class); |
|
|
|
|
|
|
|
|
|
|
|
private final List<Callback> callbackInstances = new ArrayList<Callback>(); |
|
|
|
private static final Class<?>[] CALLBACK_TYPES = { BeanMethodInterceptor.class, |
|
|
|
|
|
|
|
DisposableBeanMethodInterceptor.class, NoOp.class }; |
|
|
|
|
|
|
|
|
|
|
|
private final List<Class<? extends Callback>> callbackTypes = new ArrayList<Class<? extends Callback>>(); |
|
|
|
private static final CallbackFilter CALLBACK_FILTER = new CallbackFilter() { |
|
|
|
|
|
|
|
|
|
|
|
private final CallbackFilter callbackFilter; |
|
|
|
public int accept(Method candidateMethod) { |
|
|
|
|
|
|
|
// Set up the callback filter to return the index of the BeanMethodInterceptor when
|
|
|
|
|
|
|
|
// handling a @Bean-annotated method; otherwise, return index of the NoOp callback.
|
|
|
|
|
|
|
|
if (BeanAnnotationHelper.isBeanAnnotated(candidateMethod)) { |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (DisposableBeanMethodInterceptor.isDestroyMethod(candidateMethod)) { |
|
|
|
|
|
|
|
return 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return 2; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static final Callback DISPOSABLE_BEAN_METHOD_INTERCEPTOR = new DisposableBeanMethodInterceptor(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final Callback[] callbackInstances; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
@ -66,28 +81,11 @@ class ConfigurationClassEnhancer { |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public ConfigurationClassEnhancer(ConfigurableBeanFactory beanFactory) { |
|
|
|
public ConfigurationClassEnhancer(ConfigurableBeanFactory beanFactory) { |
|
|
|
Assert.notNull(beanFactory, "BeanFactory must not be null"); |
|
|
|
Assert.notNull(beanFactory, "BeanFactory must not be null"); |
|
|
|
|
|
|
|
// Callback instances must be ordered in the same way as CALLBACK_TYPES and CALLBACK_FILTER
|
|
|
|
this.callbackInstances.add(new BeanMethodInterceptor(beanFactory)); |
|
|
|
this.callbackInstances = new Callback[] { |
|
|
|
this.callbackInstances.add(new DisposableBeanMethodInterceptor()); |
|
|
|
new BeanMethodInterceptor(beanFactory), |
|
|
|
this.callbackInstances.add(NoOp.INSTANCE); |
|
|
|
DISPOSABLE_BEAN_METHOD_INTERCEPTOR, |
|
|
|
|
|
|
|
NoOp.INSTANCE }; |
|
|
|
for (Callback callback : this.callbackInstances) { |
|
|
|
|
|
|
|
this.callbackTypes.add(callback.getClass()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set up the callback filter to return the index of the BeanMethodInterceptor when
|
|
|
|
|
|
|
|
// handling a @Bean-annotated method; otherwise, return index of the NoOp callback.
|
|
|
|
|
|
|
|
callbackFilter = new CallbackFilter() { |
|
|
|
|
|
|
|
public int accept(Method candidateMethod) { |
|
|
|
|
|
|
|
if (BeanAnnotationHelper.isBeanAnnotated(candidateMethod)) { |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (DisposableBeanMethodInterceptor.isDestroyMethod(candidateMethod)) { |
|
|
|
|
|
|
|
return 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return 2; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
@ -135,15 +133,11 @@ class ConfigurationClassEnhancer { |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private Enhancer newEnhancer(Class<?> superclass) { |
|
|
|
private Enhancer newEnhancer(Class<?> superclass) { |
|
|
|
Enhancer enhancer = new Enhancer(); |
|
|
|
Enhancer enhancer = new Enhancer(); |
|
|
|
// Because callbackFilter and callbackTypes are dynamically populated
|
|
|
|
|
|
|
|
// there's no opportunity for caching. This does not appear to be causing
|
|
|
|
|
|
|
|
// any performance problem.
|
|
|
|
|
|
|
|
enhancer.setUseCache(false); |
|
|
|
|
|
|
|
enhancer.setSuperclass(superclass); |
|
|
|
enhancer.setSuperclass(superclass); |
|
|
|
enhancer.setInterfaces(new Class[] {EnhancedConfiguration.class}); |
|
|
|
enhancer.setInterfaces(new Class[] {EnhancedConfiguration.class}); |
|
|
|
enhancer.setUseFactory(false); |
|
|
|
enhancer.setUseFactory(false); |
|
|
|
enhancer.setCallbackFilter(this.callbackFilter); |
|
|
|
enhancer.setCallbackFilter(CALLBACK_FILTER); |
|
|
|
enhancer.setCallbackTypes(this.callbackTypes.toArray(new Class[this.callbackTypes.size()])); |
|
|
|
enhancer.setCallbackTypes(CALLBACK_TYPES); |
|
|
|
return enhancer; |
|
|
|
return enhancer; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -154,7 +148,7 @@ class ConfigurationClassEnhancer { |
|
|
|
private Class<?> createClass(Enhancer enhancer) { |
|
|
|
private Class<?> createClass(Enhancer enhancer) { |
|
|
|
Class<?> subclass = enhancer.createClass(); |
|
|
|
Class<?> subclass = enhancer.createClass(); |
|
|
|
// registering callbacks statically (as opposed to threadlocal) is critical for usage in an OSGi env (SPR-5932)
|
|
|
|
// registering callbacks statically (as opposed to threadlocal) is critical for usage in an OSGi env (SPR-5932)
|
|
|
|
Enhancer.registerStaticCallbacks(subclass, this.callbackInstances.toArray(new Callback[this.callbackInstances.size()])); |
|
|
|
Enhancer.registerStaticCallbacks(subclass, this.callbackInstances); |
|
|
|
return subclass; |
|
|
|
return subclass; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -216,8 +210,19 @@ class ConfigurationClassEnhancer { |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private static class BeanMethodInterceptor implements MethodInterceptor { |
|
|
|
private static class BeanMethodInterceptor implements MethodInterceptor { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static final Class<?>[] CALLBACK_TYPES = { |
|
|
|
|
|
|
|
GetObjectMethodInterceptor.class, NoOp.class }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static final CallbackFilter CALLBACK_FITLER = new CallbackFilter() { |
|
|
|
|
|
|
|
public int accept(Method method) { |
|
|
|
|
|
|
|
return method.getName().equals("getObject") ? 0 : 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final ConfigurableBeanFactory beanFactory; |
|
|
|
private final ConfigurableBeanFactory beanFactory; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public BeanMethodInterceptor(ConfigurableBeanFactory beanFactory) { |
|
|
|
public BeanMethodInterceptor(ConfigurableBeanFactory beanFactory) { |
|
|
|
this.beanFactory = beanFactory; |
|
|
|
this.beanFactory = beanFactory; |
|
|
|
} |
|
|
|
} |
|
|
@ -328,26 +333,18 @@ class ConfigurationClassEnhancer { |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private Object enhanceFactoryBean(Class<?> fbClass, String beanName) throws InstantiationException, IllegalAccessException { |
|
|
|
private Object enhanceFactoryBean(Class<?> fbClass, String beanName) throws InstantiationException, IllegalAccessException { |
|
|
|
Enhancer enhancer = new Enhancer(); |
|
|
|
Enhancer enhancer = new Enhancer(); |
|
|
|
enhancer.setUseCache(false); |
|
|
|
|
|
|
|
enhancer.setSuperclass(fbClass); |
|
|
|
enhancer.setSuperclass(fbClass); |
|
|
|
enhancer.setUseFactory(false); |
|
|
|
enhancer.setUseFactory(false); |
|
|
|
enhancer.setCallbackFilter(new CallbackFilter() { |
|
|
|
enhancer.setCallbackFilter(CALLBACK_FITLER); |
|
|
|
public int accept(Method method) { |
|
|
|
// Callback instances must be ordered in the same way as CALLBACK_TYPES and CALLBACK_FILTER
|
|
|
|
return method.getName().equals("getObject") ? 0 : 1; |
|
|
|
Callback[] callbackInstances = new Callback[] { |
|
|
|
} |
|
|
|
new GetObjectMethodInterceptor(this.beanFactory, beanName), |
|
|
|
}); |
|
|
|
NoOp.INSTANCE |
|
|
|
List<Callback> callbackInstances = new ArrayList<Callback>(); |
|
|
|
}; |
|
|
|
callbackInstances.add(new GetObjectMethodInterceptor(this.beanFactory, beanName)); |
|
|
|
|
|
|
|
callbackInstances.add(NoOp.INSTANCE); |
|
|
|
enhancer.setCallbackTypes(CALLBACK_TYPES); |
|
|
|
|
|
|
|
|
|
|
|
List<Class<? extends Callback>> callbackTypes = new ArrayList<Class<? extends Callback>>(); |
|
|
|
|
|
|
|
for (Callback callback : callbackInstances) { |
|
|
|
|
|
|
|
callbackTypes.add(callback.getClass()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enhancer.setCallbackTypes(callbackTypes.toArray(new Class[callbackTypes.size()])); |
|
|
|
|
|
|
|
Class<?> fbSubclass = enhancer.createClass(); |
|
|
|
Class<?> fbSubclass = enhancer.createClass(); |
|
|
|
Enhancer.registerCallbacks(fbSubclass, callbackInstances.toArray(new Callback[callbackInstances.size()])); |
|
|
|
Enhancer.registerCallbacks(fbSubclass, callbackInstances); |
|
|
|
return fbSubclass.newInstance(); |
|
|
|
return fbSubclass.newInstance(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|