ConfigurationClassPostProcessor programmatically registers unified ImportAwareBeanPostProcessor

Issue: SPR-14931
This commit is contained in:
Juergen Hoeller 2016-12-20 12:16:16 +01:00
parent 30df137273
commit f6b2a21206
3 changed files with 21 additions and 77 deletions

View File

@ -151,7 +151,6 @@ class ConfigurationClassEnhancer {
* must remain public in order to allow access to subclasses generated from other * must remain public in order to allow access to subclasses generated from other
* packages (i.e. user code). * packages (i.e. user code).
*/ */
@FunctionalInterface
public interface EnhancedConfiguration extends BeanFactoryAware { public interface EnhancedConfiguration extends BeanFactoryAware {
} }
@ -160,7 +159,6 @@ class ConfigurationClassEnhancer {
* Conditional {@link Callback}. * Conditional {@link Callback}.
* @see ConditionalCallbackFilter * @see ConditionalCallbackFilter
*/ */
@FunctionalInterface
private interface ConditionalCallback extends Callback { private interface ConditionalCallback extends Callback {
boolean isMatch(Method candidateMethod); boolean isMatch(Method candidateMethod);

View File

@ -36,12 +36,9 @@ import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.beans.factory.config.SingletonBeanRegistry; import org.springframework.beans.factory.config.SingletonBeanRegistry;
@ -53,7 +50,6 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.EnvironmentAware; import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware; import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ConfigurationClassEnhancer.EnhancedConfiguration; import org.springframework.context.annotation.ConfigurationClassEnhancer.EnhancedConfiguration;
@ -91,15 +87,9 @@ import static org.springframework.context.annotation.AnnotationConfigUtils.*;
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor, public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware { PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
private static final String IMPORT_AWARE_PROCESSOR_BEAN_NAME =
ConfigurationClassPostProcessor.class.getName() + ".importAwareProcessor";
private static final String IMPORT_REGISTRY_BEAN_NAME = private static final String IMPORT_REGISTRY_BEAN_NAME =
ConfigurationClassPostProcessor.class.getName() + ".importRegistry"; ConfigurationClassPostProcessor.class.getName() + ".importRegistry";
private static final String ENHANCED_CONFIGURATION_PROCESSOR_BEAN_NAME =
ConfigurationClassPostProcessor.class.getName() + ".enhancedConfigurationProcessor";
private final Log logger = LogFactory.getLog(getClass()); private final Log logger = LogFactory.getLog(getClass());
@ -224,14 +214,6 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
*/ */
@Override @Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
RootBeanDefinition iabpp = new RootBeanDefinition(ImportAwareBeanPostProcessor.class);
iabpp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(IMPORT_AWARE_PROCESSOR_BEAN_NAME, iabpp);
RootBeanDefinition ecbpp = new RootBeanDefinition(EnhancedConfigurationBeanPostProcessor.class);
ecbpp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(ENHANCED_CONFIGURATION_PROCESSOR_BEAN_NAME, ecbpp);
int registryId = System.identityHashCode(registry); int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) { if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException( throw new IllegalStateException(
@ -263,7 +245,9 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
// Simply call processConfigurationClasses lazily at this point then. // Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory); processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
} }
enhanceConfigurationClasses(beanFactory); enhanceConfigurationClasses(beanFactory);
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
} }
/** /**
@ -422,18 +406,22 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
} }
private static class ImportAwareBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware, PriorityOrdered { private static class ImportAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
private BeanFactory beanFactory; private final BeanFactory beanFactory;
@Override public ImportAwareBeanPostProcessor(BeanFactory beanFactory) {
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory; this.beanFactory = beanFactory;
} }
@Override @Override
public int getOrder() { public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {
return Ordered.HIGHEST_PRECEDENCE; // Inject the BeanFactory before AutowiredAnnotationBeanPostProcessor's
// postProcessPropertyValues method attempts to autowire other configuration beans.
if (bean instanceof EnhancedConfiguration) {
((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory);
}
return pvs;
} }
@Override @Override
@ -454,36 +442,4 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
} }
} }
/**
* {@link InstantiationAwareBeanPostProcessorAdapter} that ensures
* {@link EnhancedConfiguration} beans are injected with the {@link BeanFactory}
* before the {@link AutowiredAnnotationBeanPostProcessor} runs (SPR-10668).
*/
private static class EnhancedConfigurationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
implements PriorityOrdered, BeanFactoryAware {
private BeanFactory beanFactory;
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {
// Inject the BeanFactory before AutowiredAnnotationBeanPostProcessor's
// postProcessPropertyValues method attempts to auto-wire other configuration beans.
if (bean instanceof EnhancedConfiguration) {
((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory);
}
return pvs;
}
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2002-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -38,29 +38,20 @@ public class Spr10668Tests {
@Test @Test
public void testSelfInjectHierarchy() throws Exception { public void testSelfInjectHierarchy() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ChildConfig.class);
ChildConfig.class);
assertNotNull(context.getBean(MyComponent.class)); assertNotNull(context.getBean(MyComponent.class));
context.close(); context.close();
} }
@Configuration @Configuration
public static class ParentConfig implements BeanFactoryAware { public static class ParentConfig {
@Autowired(required = false) @Autowired(required = false)
MyComponent component; MyComponent component;
public ParentConfig() {
System.out.println("Parent " + getClass());
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("BFA " + getClass());
}
} }
@Configuration @Configuration
public static class ChildConfig extends ParentConfig { public static class ChildConfig extends ParentConfig {
@ -68,12 +59,11 @@ public class Spr10668Tests {
public MyComponentImpl myComponent() { public MyComponentImpl myComponent() {
return new MyComponentImpl(); return new MyComponentImpl();
} }
} }
public static interface MyComponent {
}
public static class MyComponentImpl implements MyComponent { public interface MyComponent {}
}
public static class MyComponentImpl implements MyComponent {}
} }