diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java index 377dc272e8..3986803b15 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java @@ -45,25 +45,41 @@ public class AnnotatedBeanDefinitionReader { private final BeanDefinitionRegistry registry; - private Environment environment = new StandardEnvironment(); + private Environment environment; private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator(); private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver(); /** - * Create a new {@code AnnotatedBeanDefinitionReader} for the given bean factory. + * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry. + * If the registry is {@link EnvironmentCapable}, e.g. is an {@code ApplicationContext}, + * the {@link Environment} will be inherited, otherwise a new + * {@link StandardEnvironment} will be created and used. * @param registry the {@code BeanFactory} to load bean definitions into, * in the form of a {@code BeanDefinitionRegistry} + * @see #AnnotatedBeanDefinitionReader(BeanDefinitionRegistry, Environment) + * @see #setEnvironment(Environment) */ public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) { - Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); - this.registry = registry; + this(registry, getOrCreateEnvironment(registry)); + } - // Inherit Environment if possible - if (this.registry instanceof EnvironmentCapable) { - this.environment = ((EnvironmentCapable) this.registry).getEnvironment(); - } + /** + * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry and using + * the given {@link Environment}. + * @param registry the {@code BeanFactory} to load bean definitions into, + * in the form of a {@code BeanDefinitionRegistry} + * @param environment the {@code Environment} to use when evaluating bean definition + * profiles. + * @since 3.1 + */ + public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) { + Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); + Assert.notNull(environment, "Environment must not be null"); + + this.registry = registry; + this.environment = environment; AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); } @@ -144,4 +160,18 @@ public class AnnotatedBeanDefinitionReader { definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); } + + + /** + * Get the Environment from the given registry if possible, otherwise return a new + * StandardEnvironment. + */ + private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry) { + Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); + if (registry instanceof EnvironmentCapable) { + return ((EnvironmentCapable) registry).getEnvironment(); + } + return new StandardEnvironment(); + } + } diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java index 13d46584c5..914b9d9ce7 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java @@ -47,9 +47,9 @@ import org.springframework.util.Assert; */ public class AnnotationConfigApplicationContext extends GenericApplicationContext { - private final AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(this); + private final AnnotatedBeanDefinitionReader reader; - private final ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this); + private final ClassPathBeanDefinitionScanner scanner; /** @@ -57,7 +57,8 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex * through {@link #register} calls and then manually {@linkplain #refresh refreshed}. */ public AnnotationConfigApplicationContext() { - this.delegateEnvironment(super.getEnvironment()); + this.reader = new AnnotatedBeanDefinitionReader(this); + this.scanner = new ClassPathBeanDefinitionScanner(this); } /** @@ -92,10 +93,6 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex @Override public void setEnvironment(ConfigurableEnvironment environment) { super.setEnvironment(environment); - delegateEnvironment(environment); - } - - private void delegateEnvironment(ConfigurableEnvironment environment) { this.reader.setEnvironment(environment); this.scanner.setEnvironment(environment); } diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java index c931d6ee1a..d9abfacd5a 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java @@ -27,15 +27,17 @@ import org.springframework.beans.factory.support.BeanDefinitionDefaults; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanNameGenerator; +import org.springframework.core.env.Environment; import org.springframework.core.env.EnvironmentCapable; +import org.springframework.core.env.StandardEnvironment; import org.springframework.core.io.ResourceLoader; import org.springframework.util.Assert; import org.springframework.util.PatternMatchUtils; /** * A bean definition scanner that detects bean candidates on the classpath, - * registering corresponding bean definitions with a given registry (BeanFactory - * or ApplicationContext). + * registering corresponding bean definitions with a given registry ({@code BeanFactory} + * or {@code ApplicationContext}). * *

Candidate classes are detected through configurable type filters. The * default filters include classes that are annotated with Spring's @@ -73,29 +75,30 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo /** - * Create a new ClassPathBeanDefinitionScanner for the given bean factory. - * @param registry the BeanFactory to load bean definitions into, - * in the form of a BeanDefinitionRegistry + * Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory. + * @param registry the {@code BeanFactory} to load bean definitions into, in the form + * of a {@code BeanDefinitionRegistry} */ public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) { this(registry, true); } /** - * Create a new ClassPathBeanDefinitionScanner for the given bean factory. - *

If the passed-in bean factory does not only implement the BeanDefinitionRegistry - * interface but also the ResourceLoader interface, it will be used as default - * ResourceLoader as well. This will usually be the case for - * {@link org.springframework.context.ApplicationContext} implementations. - *

If given a plain BeanDefinitionRegistry, the default ResourceLoader will be a - * {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver}. + * Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory. + *

If the passed-in bean factory does not only implement the + * {@code BeanDefinitionRegistry} interface but also the {@code ResourceLoader} + * interface, it will be used as default {@code ResourceLoader} as well. This will + * usually be the case for {@link org.springframework.context.ApplicationContext} + * implementations. + *

If given a plain {@code BeanDefinitionRegistry}, the default {@code ResourceLoader} + * will be a {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver}. *

If the the passed-in bean factory also implements {@link EnvironmentCapable} its * environment will be used by this reader. Otherwise, the reader will initialize and * use a {@link org.springframework.core.env.StandardEnvironment}. All - * ApplicationContext implementations are EnvironmentCapable, while normal BeanFactory - * implementations are not. - * @param registry the BeanFactory to load bean definitions into, - * in the form of a BeanDefinitionRegistry + * {@code ApplicationContext} implementations are {@code EnvironmentCapable}, while + * normal {@code BeanFactory} implementations are not. + * @param registry the {@code BeanFactory} to load bean definitions into, in the form + * of a {@code BeanDefinitionRegistry} * @param useDefaultFilters whether to include the default filters for the * {@link org.springframework.stereotype.Component @Component}, * {@link org.springframework.stereotype.Repository @Repository}, @@ -106,7 +109,33 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo * @see #setEnvironment */ public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) { - super(useDefaultFilters); + this(registry, useDefaultFilters, getOrCreateEnvironment(registry)); + } + + /** + * Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory and + * using the given {@link Environment} when evaluating bean definition profile metadata. + *

If the passed-in bean factory does not only implement the {@code + * BeanDefinitionRegistry} interface but also the {@link ResourceLoader} interface, it + * will be used as default {@code ResourceLoader} as well. This will usually be the + * case for {@link org.springframework.context.ApplicationContext} implementations. + *

If given a plain {@code BeanDefinitionRegistry}, the default {@code ResourceLoader} + * will be a {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver}. + * @param registry the {@code BeanFactory} to load bean definitions into, in the form + * of a {@code BeanDefinitionRegistry} + * @param useDefaultFilters whether to include the default filters for the + * @param environment the Spring {@link Environment} to use when evaluating bean + * definition profile metadata. + * {@link org.springframework.stereotype.Component @Component}, + * {@link org.springframework.stereotype.Repository @Repository}, + * {@link org.springframework.stereotype.Service @Service}, and + * {@link org.springframework.stereotype.Controller @Controller} stereotype + * annotations. + * @since 3.1 + * @see #setResourceLoader + */ + public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment) { + super(useDefaultFilters, environment); Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); this.registry = registry; @@ -115,11 +144,6 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo if (this.registry instanceof ResourceLoader) { setResourceLoader((ResourceLoader) this.registry); } - - // Inherit Environment if possible - if (this.registry instanceof EnvironmentCapable) { - setEnvironment(((EnvironmentCapable) this.registry).getEnvironment()); - } } @@ -307,4 +331,17 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo newDefinition.equals(existingDefinition)); // scanned equivalent class twice } + + /** + * Get the Environment from the given registry if possible, otherwise return a new + * StandardEnvironment. + */ + private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry) { + Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); + if (registry instanceof EnvironmentCapable) { + return ((EnvironmentCapable) registry).getEnvironment(); + } + return new StandardEnvironment(); + } + } diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java index d077ac89b2..877ba1bdda 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java @@ -73,7 +73,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC protected final Log logger = LogFactory.getLog(getClass()); - private Environment environment = new StandardEnvironment(); + private Environment environment; private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); @@ -95,9 +95,14 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC * @see #registerDefaultFilters() */ public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters) { + this(useDefaultFilters, new StandardEnvironment()); + } + + public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters, Environment environment) { if (useDefaultFilters) { registerDefaultFilters(); } + this.environment = environment; }