diff --git a/spring-context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java b/spring-context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java
index b660b0355b..a19488d93c 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java
@@ -92,7 +92,7 @@ public class AnnotatedBeanDefinitionReader {
/**
* Set the Environment to use when evaluating whether
- * {@link Profile @Profile}-annotated component classes should be registered.
+ * {@link Conditional @Conditional}-annotated component classes should be registered.
*
The default is a {@link StandardEnvironment}.
* @see #registerBean(Class, String, Class...)
*/
@@ -133,8 +133,7 @@ public class AnnotatedBeanDefinitionReader {
public void registerBean(Class> annotatedClass, String name, Class extends Annotation>... qualifiers) {
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
- if (ConditionalAnnotationHelper.shouldSkip(abd, this.registry,
- this.environment, this.beanNameGenerator)) {
+ if (ConditionEvaluator.get(abd.getMetadata(), true).shouldSkip(this.registry, this.environment)) {
return;
}
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java
index a016b88554..b673b40fc4 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java
@@ -31,6 +31,7 @@ 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.core.type.classreading.MetadataReader;
import org.springframework.util.Assert;
import org.springframework.util.PatternMatchUtils;
@@ -52,7 +53,6 @@ import org.springframework.util.PatternMatchUtils;
* @author Mark Fisher
* @author Juergen Hoeller
* @author Chris Beams
- * @author Phillip Webb
* @since 2.5
* @see AnnotationConfigApplicationContext#scan
* @see org.springframework.stereotype.Component
@@ -262,6 +262,12 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo
return beanDefinitions;
}
+ @Override
+ protected boolean isConditionMatch(MetadataReader metadataReader) {
+ return !ConditionEvaluator.get(metadataReader.getAnnotationMetadata(), true).shouldSkip(
+ getRegistry(), getEnvironment());
+ }
+
/**
* Apply further settings to the given bean definition,
* beyond the contents retrieved from scanning the component class.
@@ -299,10 +305,6 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo
* bean definition has been found for the specified name
*/
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
- if (ConditionalAnnotationHelper.shouldSkip(beanDefinition, getRegistry(),
- getEnvironment(), this.beanNameGenerator)) {
- return false;
- }
if (!this.registry.containsBeanDefinition(beanName)) {
return true;
}
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java
index a12e9ab190..5c66d8f211 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java
@@ -25,12 +25,10 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ResourceLoaderAware;
-import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.env.EnvironmentCapable;
import org.springframework.core.env.StandardEnvironment;
@@ -39,7 +37,6 @@ import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
-import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
@@ -159,7 +156,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
/**
* Set the Environment to use when resolving placeholders and evaluating
- * {@link Profile @Profile}-annotated component classes.
+ * {@link Conditional @Conditional}-annotated component classes.
*
The default is a {@link StandardEnvironment}
* @param environment the Environment to use
*/
@@ -333,17 +330,23 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
}
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
- AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
- if (!metadata.isAnnotated(Profile.class.getName())) {
- return true;
- }
- AnnotationAttributes profile = MetadataUtils.attributesFor(metadata, Profile.class);
- return this.environment.acceptsProfiles(profile.getStringArray("value"));
+ return isConditionMatch(metadataReader);
}
}
return false;
}
+ /**
+ * Determine whether the given class is a candidate component based on any
+ * {@code @Conditional} annotations.
+ * @param metadataReader the ASM ClassReader for the class
+ * @return whether the class qualifies as a candidate component
+ */
+ protected boolean isConditionMatch(MetadataReader metadataReader) {
+ return !ConditionEvaluator.get(metadataReader.getAnnotationMetadata(), true).shouldSkip(
+ null, getEnvironment());
+ }
+
/**
* Determine whether the given bean definition qualifies as candidate.
*
The default implementation checks whether the class is concrete
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConditionContext.java b/spring-context/src/main/java/org/springframework/context/annotation/ConditionContext.java
index 564586501c..bca2fc8f1b 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/ConditionContext.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ConditionContext.java
@@ -31,8 +31,8 @@ public interface ConditionContext {
/**
* Returns the {@link BeanDefinitionRegistry} that will hold the bean definition
- * should the condition match.
- * @return the registry (never {@code null})
+ * should the condition match or {@code null} if the registry is not available.
+ * @return the registry or {@code null}
*/
BeanDefinitionRegistry getRegistry();
@@ -45,13 +45,11 @@ public interface ConditionContext {
/**
* Returns the {@link ConfigurableListableBeanFactory} that will hold the bean
- * definition should the condition match. If a
- * {@link ConfigurableListableBeanFactory} is unavailable an
- * {@link IllegalStateException} will be thrown.
- * @return the bean factory
- * @throws IllegalStateException if the bean factory could not be obtained
+ * definition should the condition match or {@code null} if the bean factory is
+ * not available.
+ * @return the bean factory or {@code null}
*/
- ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
+ ConfigurableListableBeanFactory getBeanFactory();
/**
* Returns the {@link ResourceLoader} currently being used or {@code null} if the
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConditionEvaluator.java b/spring-context/src/main/java/org/springframework/context/annotation/ConditionEvaluator.java
new file mode 100644
index 0000000000..2f7342f8dd
--- /dev/null
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ConditionEvaluator.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2002-2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.context.annotation;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.core.env.Environment;
+import org.springframework.core.env.EnvironmentCapable;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+import org.springframework.core.type.AnnotationMetadata;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.MultiValueMap;
+
+/**
+ * Utility class used to evaluate {@link Conditional} annotations.
+ *
+ * @author Phillip Webb
+ * @since 4.0
+ */
+abstract class ConditionEvaluator {
+
+ private static final String CONDITIONAL_ANNOTATION = Conditional.class.getName();
+
+ private static final ConditionEvaluator NONE = new ConditionEvaluator() {
+
+ @Override
+ public boolean shouldSkip(BeanDefinitionRegistry registry, Environment environment) {
+ return false;
+ }
+
+ };
+
+
+ /**
+ * Evaluate if any condition does not match and hence registration should be skipped.
+ * @param registry the registry or {@code null}
+ * @param environment the environment or {@code null}
+ * @return if the registration should be skipped
+ */
+ public abstract boolean shouldSkip(BeanDefinitionRegistry registry,
+ Environment environment);
+
+
+ /**
+ * Returns a {@link ConditionEvaluator} instance of the specified metadata.
+ * @param metadata the metadata to test
+ * @param deferIfConfigurationCandidate if the evaluator should be deferred when the
+ * metadata is from a {@code @Configuration} candidate.
+ * @return the evaluator instance
+ */
+ public static ConditionEvaluator get(AnnotatedTypeMetadata metadata,
+ boolean deferIfConfigurationCandidate) {
+ if (metadata == null || !metadata.isAnnotated(CONDITIONAL_ANNOTATION)) {
+ // Shortcut to save always creating a ConditionEvaluator
+ return NONE;
+ }
+
+ // Defer @Conditional @Configuration classes until later when the
+ // ConfigurationClassPostProcessor will evaluate them. Allows @Conditional
+ // implementations that inspect beans created by @Configuration to work
+ if (deferIfConfigurationCandidate && metadata instanceof AnnotationMetadata
+ && ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
+ return NONE;
+ }
+
+ return new ConditionEvaluatorImpl(metadata);
+ }
+
+
+ /**
+ * Implementation of {@link ConditionEvaluator}.
+ */
+ private static class ConditionEvaluatorImpl extends ConditionEvaluator {
+
+ private AnnotatedTypeMetadata metadata;
+
+
+ public ConditionEvaluatorImpl(AnnotatedTypeMetadata metadata) {
+ this.metadata = metadata;
+ }
+
+
+ @Override
+ public boolean shouldSkip(BeanDefinitionRegistry registry, Environment environment) {
+ ConditionContext context = new ConditionContextImpl(registry, environment);
+ if (this.metadata != null) {
+ for (String[] conditionClasses : getConditionClasses(metadata)) {
+ for (String conditionClass : conditionClasses) {
+ if (!getCondition(conditionClass, context.getClassLoader()).matches(
+ context, metadata)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static List getConditionClasses(AnnotatedTypeMetadata metadata) {
+ MultiValueMap attributes = metadata.getAllAnnotationAttributes(
+ CONDITIONAL_ANNOTATION, true);
+ Object values = attributes == null ? null : attributes.get("value");
+ return (List) (values == null ? Collections.emptyList() : values);
+ }
+
+ private static Condition getCondition(String conditionClassName,
+ ClassLoader classloader) {
+ Class> conditionClass = ClassUtils.resolveClassName(conditionClassName,
+ classloader);
+ return (Condition) BeanUtils.instantiateClass(conditionClass);
+ }
+ }
+
+ /**
+ * Implementation of a {@link ConditionContext}.
+ */
+ private static class ConditionContextImpl implements ConditionContext {
+
+ private BeanDefinitionRegistry registry;
+
+ private ConfigurableListableBeanFactory beanFactory;
+
+ private Environment environment;
+
+
+ public ConditionContextImpl(BeanDefinitionRegistry registry,
+ Environment environment) {
+ this.registry = registry;
+ this.beanFactory = deduceBeanFactory(registry);
+ this.environment = environment;
+ if (this.environment == null) {
+ this.environment = deduceEnvironment(registry);
+ }
+ }
+
+
+ private ConfigurableListableBeanFactory deduceBeanFactory(Object source) {
+ if (source == null) {
+ return null;
+ }
+ if (source instanceof ConfigurableListableBeanFactory) {
+ return (ConfigurableListableBeanFactory) source;
+ }
+ else if (source instanceof ConfigurableApplicationContext) {
+ return deduceBeanFactory(((ConfigurableApplicationContext) source).getBeanFactory());
+ }
+ return null;
+ }
+
+ private Environment deduceEnvironment(BeanDefinitionRegistry registry) {
+ if (registry == null) {
+ return null;
+ }
+ if (registry instanceof EnvironmentCapable) {
+ return ((EnvironmentCapable) registry).getEnvironment();
+ }
+ return null;
+ }
+
+ @Override
+ public BeanDefinitionRegistry getRegistry() {
+ return this.registry;
+ }
+
+ @Override
+ public Environment getEnvironment() {
+ return this.environment;
+ }
+
+ @Override
+ public ConfigurableListableBeanFactory getBeanFactory() {
+ Assert.state(this.beanFactory != null, "Unable to locate the BeanFactory");
+ return this.beanFactory;
+ }
+
+ @Override
+ public ResourceLoader getResourceLoader() {
+ if (registry instanceof ResourceLoader) {
+ return (ResourceLoader) registry;
+ }
+ return null;
+ }
+
+ @Override
+ public ClassLoader getClassLoader() {
+ ResourceLoader resourceLoader = getResourceLoader();
+ return (resourceLoader == null ? null : resourceLoader.getClassLoader());
+ }
+ }
+
+}
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConditionalAnnotationHelper.java b/spring-context/src/main/java/org/springframework/context/annotation/ConditionalAnnotationHelper.java
deleted file mode 100644
index 0eba197672..0000000000
--- a/spring-context/src/main/java/org/springframework/context/annotation/ConditionalAnnotationHelper.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright 2002-2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.context.annotation;
-
-import java.util.Collections;
-import java.util.List;
-
-import org.springframework.beans.BeanUtils;
-import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
-import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
-import org.springframework.beans.factory.support.BeanNameGenerator;
-import org.springframework.context.ConfigurableApplicationContext;
-import org.springframework.core.env.Environment;
-import org.springframework.core.env.EnvironmentCapable;
-import org.springframework.core.io.ResourceLoader;
-import org.springframework.core.type.AnnotatedTypeMetadata;
-import org.springframework.util.Assert;
-import org.springframework.util.ClassUtils;
-import org.springframework.util.MultiValueMap;
-
-/**
- * Helper class used to determine if registration should be skipped based due to a
- * {@code @Conditional} annotation.
- *
- * @author Phillip Webb
- * @since 4.0
- * @see Conditional
- */
-abstract class ConditionalAnnotationHelper {
-
- private static final String CONDITIONAL_ANNOTATION = Conditional.class.getName();
-
-
- public static boolean shouldSkip(BeanDefinition beanDefinition,
- BeanDefinitionRegistry registry, Environment environment,
- BeanNameGenerator beanNameGenerator) {
- if (hasCondition(getMetadata(beanDefinition))) {
- ConditionContextImpl context = new ConditionContextImpl(registry,
- environment, beanNameGenerator);
- return shouldSkip(getMetadata(beanDefinition), context);
- }
- return false;
- }
-
- public static boolean shouldSkip(BeanMethod beanMethod,
- BeanDefinitionRegistry registry, Environment environment,
- BeanNameGenerator beanNameGenerator) {
- if (hasCondition(getMetadata(beanMethod))) {
- ConditionContextImpl context = new ConditionContextImpl(registry,
- environment, beanNameGenerator);
- return shouldSkip(getMetadata(beanMethod), context);
- }
- return false;
- }
-
- public static boolean shouldSkip(ConfigurationClass configurationClass,
- BeanDefinitionRegistry registry, Environment environment,
- BeanNameGenerator beanNameGenerator) {
- if (hasCondition(configurationClass)) {
- ConditionContextImpl context = new ConditionContextImpl(registry,
- environment, beanNameGenerator);
- return shouldSkip(configurationClass, context);
- }
- return false;
- }
-
- public static boolean shouldSkip(ConfigurationClass configClass,
- ConditionContextImpl context) {
- if (configClass == null) {
- return false;
- }
- return shouldSkip(configClass.getMetadata(), context);
- }
-
- private static boolean shouldSkip(AnnotatedTypeMetadata metadata,
- ConditionContextImpl context) {
- if (metadata != null) {
- for (String[] conditionClasses : getConditionClasses(metadata)) {
- for (String conditionClass : conditionClasses) {
- if (!getCondition(conditionClass, context.getClassLoader()).matches(
- context, metadata)) {
- return true;
- }
- }
- }
- }
- return false;
- }
-
- private static AnnotatedTypeMetadata getMetadata(BeanMethod beanMethod) {
- return (beanMethod == null ? null : beanMethod.getMetadata());
- }
-
- private static AnnotatedTypeMetadata getMetadata(BeanDefinition beanDefinition) {
- if (beanDefinition != null && beanDefinition instanceof AnnotatedBeanDefinition) {
- return ((AnnotatedBeanDefinition) beanDefinition).getMetadata();
- }
- return null;
- }
-
- private static boolean hasCondition(ConfigurationClass configurationClass) {
- if (configurationClass == null) {
- return false;
- }
- return hasCondition(configurationClass.getMetadata())
- || hasCondition(configurationClass.getImportedBy());
- }
-
- private static boolean hasCondition(AnnotatedTypeMetadata metadata) {
- return (metadata != null) && metadata.isAnnotated(CONDITIONAL_ANNOTATION);
- }
-
- @SuppressWarnings("unchecked")
- private static List getConditionClasses(AnnotatedTypeMetadata metadata) {
- MultiValueMap attributes = metadata.getAllAnnotationAttributes(
- CONDITIONAL_ANNOTATION, true);
- Object values = attributes == null ? null : attributes.get("value");
- return (List) (values == null ? Collections.emptyList() : values);
- }
-
- private static Condition getCondition(String conditionClassName,
- ClassLoader classloader) {
- Class> conditionClass = ClassUtils.resolveClassName(conditionClassName,
- classloader);
- return (Condition) BeanUtils.instantiateClass(conditionClass);
- }
-
-
- /**
- * Implementation of a {@link ConditionContext}.
- */
- private static class ConditionContextImpl implements ConditionContext {
-
- private BeanDefinitionRegistry registry;
-
- private ConfigurableListableBeanFactory beanFactory;
-
- private Environment environment;
-
-
- public ConditionContextImpl(BeanDefinitionRegistry registry,
- Environment environment, BeanNameGenerator beanNameGenerator) {
- Assert.notNull(registry, "Registry must not be null");
- this.registry = registry;
- this.beanFactory = deduceBeanFactory(registry);
- this.environment = environment;
- if (this.environment == null) {
- this.environment = deduceEnvironment(registry);
- }
- }
-
-
- private ConfigurableListableBeanFactory deduceBeanFactory(Object source) {
- if (source instanceof ConfigurableListableBeanFactory) {
- return (ConfigurableListableBeanFactory) source;
- }
- else if (source instanceof ConfigurableApplicationContext) {
- return deduceBeanFactory(((ConfigurableApplicationContext) source).getBeanFactory());
- }
- return null;
- }
-
- private Environment deduceEnvironment(BeanDefinitionRegistry registry) {
- if (registry instanceof EnvironmentCapable) {
- return ((EnvironmentCapable) registry).getEnvironment();
- }
- return null;
- }
-
- @Override
- public BeanDefinitionRegistry getRegistry() {
- return this.registry;
- }
-
- @Override
- public Environment getEnvironment() {
- return this.environment;
- }
-
- @Override
- public ConfigurableListableBeanFactory getBeanFactory() {
- Assert.state(this.beanFactory != null, "Unable to locate the BeanFactory");
- return this.beanFactory;
- }
-
- @Override
- public ResourceLoader getResourceLoader() {
- if (registry instanceof ResourceLoader) {
- return (ResourceLoader) registry;
- }
- return null;
- }
-
- @Override
- public ClassLoader getClassLoader() {
- ResourceLoader resourceLoader = getResourceLoader();
- return (resourceLoader == null ? null : resourceLoader.getClassLoader());
- }
- }
-
-}
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java
index 2e91b45d5f..3af2311e2d 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java
@@ -16,6 +16,7 @@
package org.springframework.context.annotation;
+import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
@@ -61,6 +62,9 @@ final class ConfigurationClass {
private final Map> importedResources =
new LinkedHashMap>();
+ private final Set importBeanDefinitionRegistrars =
+ new LinkedHashSet();
+
/**
* Create a new {@link ConfigurationClass} with the given name.
@@ -173,11 +177,18 @@ final class ConfigurationClass {
this.importedResources.put(importedResource, readerClass);
}
+ public void addImportBeanDefinitionRegistrar(ImportBeanDefinitionRegistrar registrar) {
+ this.importBeanDefinitionRegistrars.add(registrar);
+ }
+
+ public Set getImportBeanDefinitionRegistrars() {
+ return Collections.unmodifiableSet(importBeanDefinitionRegistrars);
+ }
+
public Map> getImportedResources() {
return this.importedResources;
}
-
public void validate(ProblemReporter problemReporter) {
// A configuration class may not be final (CGLIB limitation)
if (getMetadata().isAnnotated(Configuration.class.getName())) {
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java
index 27f417f655..1ca7538b70 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java
@@ -16,8 +16,6 @@
package org.springframework.context.annotation;
-import static org.springframework.context.annotation.MetadataUtils.attributesFor;
-
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
@@ -28,6 +26,7 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.annotation.Autowire;
@@ -52,6 +51,8 @@ import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.StringUtils;
+import static org.springframework.context.annotation.MetadataUtils.*;
+
/**
* Reads a given fully-populated set of ConfigurationClass instances, registering bean
* definitions with the given {@link BeanDefinitionRegistry} based on its contents.
@@ -84,7 +85,6 @@ class ConfigurationClassBeanDefinitionReader {
private final BeanNameGenerator importBeanNameGenerator;
-
/**
* Create a new {@link ConfigurationClassBeanDefinitionReader} instance that will be used
* to populate the given {@link BeanDefinitionRegistry}.
@@ -109,8 +109,9 @@ class ConfigurationClassBeanDefinitionReader {
* based on its contents.
*/
public void loadBeanDefinitions(Set configurationModel) {
+ TrackedConditionEvaluator conditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
- loadBeanDefinitionsForConfigurationClass(configClass);
+ loadBeanDefinitionsForConfigurationClass(configClass, conditionEvaluator);
}
}
@@ -118,7 +119,14 @@ class ConfigurationClassBeanDefinitionReader {
* Read a particular {@link ConfigurationClass}, registering bean definitions for the
* class itself, all its {@link Bean} methods
*/
- public void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass) {
+ private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
+ TrackedConditionEvaluator conditionEvaluator) {
+
+ if(conditionEvaluator.shouldSkip(configClass)) {
+ removeBeanDefinition(configClass);
+ return;
+ }
+
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
@@ -126,6 +134,17 @@ class ConfigurationClassBeanDefinitionReader {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
+ loadBeanDefinitionsFromRegistrars(configClass.getMetadata(), configClass.getImportBeanDefinitionRegistrars());
+ }
+
+ private void removeBeanDefinition(ConfigurationClass configClass) {
+ if (StringUtils.hasLength(configClass.getBeanName())) {
+ try {
+ this.registry.removeBeanDefinition(configClass.getBeanName());
+ }
+ catch (NoSuchBeanDefinitionException ex) {
+ }
+ }
}
/**
@@ -153,8 +172,8 @@ class ConfigurationClassBeanDefinitionReader {
* with the BeanDefinitionRegistry based on its contents.
*/
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
- if (ConditionalAnnotationHelper.shouldSkip(beanMethod, this.registry,
- this.environment, this.importBeanNameGenerator)) {
+ if (ConditionEvaluator.get(beanMethod.getMetadata(), false).shouldSkip(
+ this.registry, this.environment)) {
return;
}
ConfigurationClass configClass = beanMethod.getConfigurationClass();
@@ -300,6 +319,14 @@ class ConfigurationClassBeanDefinitionReader {
}
}
+ private void loadBeanDefinitionsFromRegistrars(
+ AnnotationMetadata importingClassMetadata,
+ Set importBeanDefinitionRegistrars) {
+ for (ImportBeanDefinitionRegistrar registrar : importBeanDefinitionRegistrars) {
+ registrar.registerBeanDefinitions(importingClassMetadata, this.registry);
+ }
+ }
+
/**
* {@link RootBeanDefinition} marker subclass used to signify that a bean definition
@@ -357,4 +384,32 @@ class ConfigurationClassBeanDefinitionReader {
}
}
+ /**
+ * Evaluate {@Code @Conditional} annotations, tracking results and taking into
+ * account 'imported by'.
+ */
+ private class TrackedConditionEvaluator {
+
+ private final Map skipped = new HashMap();
+
+ public boolean shouldSkip(ConfigurationClass configClass) {
+ Boolean skip = this.skipped.get(configClass);
+ if (skip == null) {
+ if (configClass.isImported()) {
+ if (shouldSkip(configClass.getImportedBy())) {
+ // The config that imported this one was skipped, therefore we are skipped
+ skip = true;
+ }
+ }
+ if (skip == null) {
+ skip = ConditionEvaluator.get(configClass.getMetadata(), false).shouldSkip(
+ registry, environment);
+ }
+ this.skipped.put(configClass, skip);
+ }
+ return skip;
+ }
+
+ }
+
}
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java
index 0ac8c31e82..b7622fc2bb 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java
@@ -76,7 +76,8 @@ import static org.springframework.context.annotation.MetadataUtils.*;
*
* This class helps separate the concern of parsing the structure of a Configuration
* class from the concern of registering BeanDefinition objects based on the
- * content of that model.
+ * content of that model (with the exception of {@code @ComponentScan} annotations which
+ * need to be registered immediately).
*
*
This ASM-based implementation avoids reflection and eager class loading in order to
* interoperate effectively with lazy class loading in a Spring ApplicationContext.
@@ -108,8 +109,6 @@ class ConfigurationClassParser {
private final BeanDefinitionRegistry registry;
- private final BeanNameGenerator beanNameGenerator;
-
private final ComponentScanAnnotationParser componentScanParser;
private final Set configurationClasses = new LinkedHashSet();
@@ -136,7 +135,6 @@ class ConfigurationClassParser {
this.environment = environment;
this.resourceLoader = resourceLoader;
this.registry = registry;
- this.beanNameGenerator = componentScanBeanNameGenerator;
this.componentScanParser = new ComponentScanAnnotationParser(
resourceLoader, environment, componentScanBeanNameGenerator, registry);
}
@@ -182,9 +180,6 @@ class ConfigurationClassParser {
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
- if (ConditionalAnnotationHelper.shouldSkip(configClass, this.registry, this.environment, this.beanNameGenerator)) {
- return;
- }
if (this.configurationClasses.contains(configClass) && configClass.getBeanName() != null) {
// Explicit bean definition found, probably replacing an import.
@@ -226,13 +221,16 @@ class ConfigurationClassParser {
AnnotationAttributes componentScan = attributesFor(metadata, ComponentScan.class);
if (componentScan != null) {
// the config class is annotated with @ComponentScan -> perform the scan immediately
- Set scannedBeanDefinitions =
- this.componentScanParser.parse(componentScan, metadata.getClassName());
+ if (!ConditionEvaluator.get(configClass.getMetadata(), false).shouldSkip(
+ this.registry, this.environment)) {
+ Set scannedBeanDefinitions =
+ this.componentScanParser.parse(componentScan, metadata.getClassName());
- // check the set of scanned definitions for any further config classes and parse recursively if necessary
- for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
- if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {
- this.parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
+ // check the set of scanned definitions for any further config classes and parse recursively if necessary
+ for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
+ if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {
+ this.parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
+ }
}
}
}
@@ -451,7 +449,7 @@ class ConfigurationClassParser {
this.resourceLoader.getClassLoader().loadClass((String) candidate));
ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
invokeAwareMethods(registrar);
- registrar.registerBeanDefinitions(importingClassMetadata, this.registry);
+ configClass.addImportBeanDefinitionRegistrar(registrar);
}
else {
// candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> process it as a @Configuration class
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java
index 944fd051f2..42f16bbd7e 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java
@@ -26,7 +26,6 @@ import java.util.Stack;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanDefinitionStoreException;
@@ -305,12 +304,8 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
registry, this.sourceExtractor, this.problemReporter, this.metadataReaderFactory,
this.resourceLoader, this.environment, this.importBeanNameGenerator);
}
- for (ConfigurationClass configurationClass : parser.getConfigurationClasses()) {
- if (!ConditionalAnnotationHelper.shouldSkip(configurationClass, registry,
- this.environment, this.importBeanNameGenerator)) {
- reader.loadBeanDefinitionsForConfigurationClass(configurationClass);
- }
- }
+
+ reader.loadBeanDefinitions(parser.getConfigurationClasses());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (singletonRegistry != null) {
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassUtils.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassUtils.java
index 9a4a682771..46a58b7eb0 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassUtils.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassWithConditionTests.java b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassWithConditionTests.java
index 49dfa4a966..6e261a0e5e 100644
--- a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassWithConditionTests.java
+++ b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassWithConditionTests.java
@@ -46,20 +46,41 @@ public class ConfigurationClassWithConditionTests {
public ExpectedException thrown = ExpectedException.none();
@Test
- public void conditionalOnBeanMatch() throws Exception {
+ public void conditionalOnMissingBeanMatch() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(BeanOneConfiguration.class, BeanTwoConfiguration.class);
ctx.refresh();
assertTrue(ctx.containsBean("bean1"));
assertFalse(ctx.containsBean("bean2"));
+ assertFalse(ctx.containsBean("configurationClassWithConditionTests.BeanTwoConfiguration"));
+ }
+
+ @Test
+ public void conditionalOnMissingBeanNoMatch() throws Exception {
+ AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
+ ctx.register(BeanTwoConfiguration.class);
+ ctx.refresh();
+ assertFalse(ctx.containsBean("bean1"));
+ assertTrue(ctx.containsBean("bean2"));
+ assertTrue(ctx.containsBean("configurationClassWithConditionTests.BeanTwoConfiguration"));
+ }
+
+ @Test
+ public void conditionalOnBeanMatch() throws Exception {
+ AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
+ ctx.register(BeanOneConfiguration.class, BeanThreeConfiguration.class);
+ ctx.refresh();
+ assertTrue(ctx.containsBean("bean1"));
+ assertTrue(ctx.containsBean("bean3"));
}
@Test
public void conditionalOnBeanNoMatch() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
- ctx.register(BeanTwoConfiguration.class);
+ ctx.register(BeanThreeConfiguration.class);
ctx.refresh();
- assertTrue(ctx.containsBean("bean2"));
+ assertFalse(ctx.containsBean("bean1"));
+ assertFalse(ctx.containsBean("bean3"));
}
@Test
@@ -105,6 +126,15 @@ public class ConfigurationClassWithConditionTests {
}
}
+ @Configuration
+ @Conditional(HasBeanOneCondition.class)
+ static class BeanThreeConfiguration {
+ @Bean
+ public ExampleBean bean3() {
+ return new ExampleBean();
+ }
+ }
+
@Configuration
@MetaConditional("test")
static class ConfigurationWithMetaCondition {
@@ -135,6 +165,14 @@ public class ConfigurationClassWithConditionTests {
}
}
+ static class HasBeanOneCondition implements Condition {
+
+ @Override
+ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
+ return context.getBeanFactory().containsBeanDefinition("bean1");
+ }
+ }
+
static class MetaConditionalFilter implements Condition {
@Override
diff --git a/spring-context/src/test/java/org/springframework/context/annotation/componentscan/simple/SimpleComponent.java b/spring-context/src/test/java/org/springframework/context/annotation/componentscan/simple/SimpleComponent.java
index 43e394b560..9d63ad60a2 100644
--- a/spring-context/src/test/java/org/springframework/context/annotation/componentscan/simple/SimpleComponent.java
+++ b/spring-context/src/test/java/org/springframework/context/annotation/componentscan/simple/SimpleComponent.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.