Improve support for @Conditional on @Configuration
Introduce new ConfigurationCondition interface allowing more fine-grained control for @Conditional when used with @Configuration beans. Primarily added so that the evaluation of conditions that inspect bean definitions can be deferred until all @Configuration classes have been parsed. Issue: SPR-10534
This commit is contained in:
@@ -45,12 +45,12 @@ public class AnnotatedBeanDefinitionReader {
|
|||||||
|
|
||||||
private final BeanDefinitionRegistry registry;
|
private final BeanDefinitionRegistry registry;
|
||||||
|
|
||||||
private Environment environment;
|
|
||||||
|
|
||||||
private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
|
private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
|
||||||
|
|
||||||
private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
|
private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
|
||||||
|
|
||||||
|
private ConditionEvaluator conditionEvaluator;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@code AnnotatedBeanDefinitionReader} for the given registry.
|
* Create a new {@code AnnotatedBeanDefinitionReader} for the given registry.
|
||||||
@@ -79,7 +79,8 @@ public class AnnotatedBeanDefinitionReader {
|
|||||||
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
|
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
|
||||||
Assert.notNull(environment, "Environment must not be null");
|
Assert.notNull(environment, "Environment must not be null");
|
||||||
this.registry = registry;
|
this.registry = registry;
|
||||||
this.environment = environment;
|
this.conditionEvaluator = new ConditionEvaluator(registry, environment,
|
||||||
|
null, null, null);
|
||||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
|
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +98,8 @@ public class AnnotatedBeanDefinitionReader {
|
|||||||
* @see #registerBean(Class, String, Class...)
|
* @see #registerBean(Class, String, Class...)
|
||||||
*/
|
*/
|
||||||
public void setEnvironment(Environment environment) {
|
public void setEnvironment(Environment environment) {
|
||||||
this.environment = environment;
|
this.conditionEvaluator = new ConditionEvaluator(this.registry, environment,
|
||||||
|
null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -133,7 +135,7 @@ public class AnnotatedBeanDefinitionReader {
|
|||||||
|
|
||||||
public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
|
public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
|
||||||
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
|
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
|
||||||
if (ConditionEvaluator.get(abd.getMetadata(), true).shouldSkip(this.registry, this.environment)) {
|
if (conditionEvaluator.shouldSkip(abd.getMetadata())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
|
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
|
||||||
|
|||||||
@@ -262,12 +262,6 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo
|
|||||||
return beanDefinitions;
|
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,
|
* Apply further settings to the given bean definition,
|
||||||
* beyond the contents retrieved from scanning the component class.
|
* beyond the contents retrieved from scanning the component class.
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import org.apache.commons.logging.LogFactory;
|
|||||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.context.ResourceLoaderAware;
|
import org.springframework.context.ResourceLoaderAware;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.core.env.EnvironmentCapable;
|
import org.springframework.core.env.EnvironmentCapable;
|
||||||
@@ -85,6 +86,8 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
|||||||
|
|
||||||
private final List<TypeFilter> excludeFilters = new LinkedList<TypeFilter>();
|
private final List<TypeFilter> excludeFilters = new LinkedList<TypeFilter>();
|
||||||
|
|
||||||
|
private ConditionEvaluator conditionEvaluator;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a ClassPathScanningCandidateComponentProvider with a {@link StandardEnvironment}.
|
* Create a ClassPathScanningCandidateComponentProvider with a {@link StandardEnvironment}.
|
||||||
@@ -162,6 +165,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
|||||||
*/
|
*/
|
||||||
public void setEnvironment(Environment environment) {
|
public void setEnvironment(Environment environment) {
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
|
this.conditionEvaluator = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -169,6 +173,13 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
|||||||
return this.environment;
|
return this.environment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link BeanDefinitionRegistry} used by this scanner or {@code null}.
|
||||||
|
*/
|
||||||
|
protected BeanDefinitionRegistry getRegistry() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the resource pattern to use when scanning the classpath.
|
* Set the resource pattern to use when scanning the classpath.
|
||||||
* This value will be appended to each base package name.
|
* This value will be appended to each base package name.
|
||||||
@@ -342,9 +353,12 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
|
|||||||
* @param metadataReader the ASM ClassReader for the class
|
* @param metadataReader the ASM ClassReader for the class
|
||||||
* @return whether the class qualifies as a candidate component
|
* @return whether the class qualifies as a candidate component
|
||||||
*/
|
*/
|
||||||
protected boolean isConditionMatch(MetadataReader metadataReader) {
|
private boolean isConditionMatch(MetadataReader metadataReader) {
|
||||||
return !ConditionEvaluator.get(metadataReader.getAnnotationMetadata(), true).shouldSkip(
|
if (this.conditionEvaluator == null) {
|
||||||
null, getEnvironment());
|
this.conditionEvaluator = new ConditionEvaluator(getRegistry(),
|
||||||
|
getEnvironment(), null, null, getResourceLoader());
|
||||||
|
}
|
||||||
|
return !conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -25,15 +25,18 @@ import org.springframework.core.type.AnnotationMetadata;
|
|||||||
* A single {@code condition} that must be {@linkplain #matches matched} in order
|
* A single {@code condition} that must be {@linkplain #matches matched} in order
|
||||||
* for a component to be registered.
|
* for a component to be registered.
|
||||||
*
|
*
|
||||||
* <p>Conditions are checked immediately before a component bean-definition is due to be
|
* <p>Conditions are checked immediately before the bean-definition is due to be
|
||||||
* registered and are free to veto registration based on any criteria that can be
|
* registered and are free to veto registration based on any criteria that can
|
||||||
* determined at that point.
|
* be determined at that point.
|
||||||
*
|
*
|
||||||
* <p>Conditions must follow the same restrictions as {@link BeanFactoryPostProcessor}
|
* <p>Conditions must follow the same restrictions as {@link BeanFactoryPostProcessor}
|
||||||
* and take care to never interact with bean instances.
|
* and take care to never interact with bean instances. For more fine-grained control
|
||||||
|
* of conditions that interact with {@code @Configuration} beans consider the
|
||||||
|
* {@link ConfigurationCondition} interface.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @since 4.0
|
* @since 4.0
|
||||||
|
* @see ConfigurationCondition
|
||||||
* @see Conditional
|
* @see Conditional
|
||||||
* @see ConditionContext
|
* @see ConditionContext
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package org.springframework.context.annotation;
|
|||||||
|
|
||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.core.io.ResourceLoader;
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
|
||||||
@@ -65,4 +66,6 @@ public interface ConditionContext {
|
|||||||
*/
|
*/
|
||||||
ClassLoader getClassLoader();
|
ClassLoader getClassLoader();
|
||||||
|
|
||||||
|
ApplicationContext getApplicationContext();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ import java.util.List;
|
|||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.core.env.EnvironmentCapable;
|
import org.springframework.core.env.EnvironmentCapable;
|
||||||
import org.springframework.core.io.ResourceLoader;
|
import org.springframework.core.io.ResourceLoader;
|
||||||
@@ -33,106 +35,93 @@ import org.springframework.util.ClassUtils;
|
|||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class used to evaluate {@link Conditional} annotations.
|
* Internal class used to evaluate {@link Conditional} annotations.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @since 4.0
|
* @since 4.0
|
||||||
*/
|
*/
|
||||||
abstract class ConditionEvaluator {
|
class ConditionEvaluator {
|
||||||
|
|
||||||
private static final String CONDITIONAL_ANNOTATION = Conditional.class.getName();
|
private static final String CONDITIONAL_ANNOTATION = Conditional.class.getName();
|
||||||
|
|
||||||
private static final ConditionEvaluator NONE = new ConditionEvaluator() {
|
|
||||||
|
|
||||||
@Override
|
private final ConditionContextImpl context;
|
||||||
public boolean shouldSkip(BeanDefinitionRegistry registry, Environment environment) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluate if any condition does not match and hence registration should be skipped.
|
* Create a new {@link ConditionEvaluator} instance.
|
||||||
* @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,
|
public ConditionEvaluator(BeanDefinitionRegistry registry, Environment environment,
|
||||||
Environment environment);
|
ApplicationContext applicationContext, ClassLoader classLoader,
|
||||||
|
ResourceLoader resourceLoader) {
|
||||||
|
this.context = new ConditionContextImpl(registry, environment,
|
||||||
/**
|
applicationContext, classLoader, resourceLoader);
|
||||||
* 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}.
|
* Determine if an item should be skipped based on {@code @Conditional} annotations.
|
||||||
|
* The {@link ConfigurationPhase} will be deduced from the type of item (i.e. a
|
||||||
|
* {@code @Configuration} class will be {@link ConfigurationPhase#PARSE_CONFIGURATION})
|
||||||
|
* @param metadata the meta data
|
||||||
|
* @return if the item should be skipped
|
||||||
*/
|
*/
|
||||||
private static class ConditionEvaluatorImpl extends ConditionEvaluator {
|
public boolean shouldSkip(AnnotatedTypeMetadata metadata) {
|
||||||
|
return shouldSkip(metadata, null);
|
||||||
|
}
|
||||||
|
|
||||||
private AnnotatedTypeMetadata metadata;
|
/**
|
||||||
|
* Determine if an item should be skipped based on {@code @Conditional} annotations.
|
||||||
|
* @param metadata the meta data
|
||||||
public ConditionEvaluatorImpl(AnnotatedTypeMetadata metadata) {
|
* @param phase the phase of the call
|
||||||
this.metadata = metadata;
|
* @return if the item should be skipped
|
||||||
|
*/
|
||||||
|
public boolean shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationPhase phase) {
|
||||||
|
if (metadata == null || !metadata.isAnnotated(CONDITIONAL_ANNOTATION)) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (phase == null) {
|
||||||
|
if (metadata instanceof AnnotationMetadata &&
|
||||||
|
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
|
||||||
|
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
|
||||||
|
}
|
||||||
|
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
for (String[] conditionClasses : getConditionClasses(metadata)) {
|
||||||
public boolean shouldSkip(BeanDefinitionRegistry registry, Environment environment) {
|
for (String conditionClass : conditionClasses) {
|
||||||
ConditionContext context = new ConditionContextImpl(registry, environment);
|
Condition condition = getCondition(conditionClass, context.getClassLoader());
|
||||||
if (this.metadata != null) {
|
ConfigurationPhase requiredPhase = null;
|
||||||
for (String[] conditionClasses : getConditionClasses(metadata)) {
|
if (condition instanceof ConfigurationCondition) {
|
||||||
for (String conditionClass : conditionClasses) {
|
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
|
||||||
if (!getCondition(conditionClass, context.getClassLoader()).matches(
|
}
|
||||||
context, metadata)) {
|
if (requiredPhase == null || requiredPhase == phase) {
|
||||||
return true;
|
if (!condition.matches(context, metadata)) {
|
||||||
}
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private static List<String[]> getConditionClasses(AnnotatedTypeMetadata metadata) {
|
|
||||||
MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(
|
|
||||||
CONDITIONAL_ANNOTATION, true);
|
|
||||||
Object values = attributes == null ? null : attributes.get("value");
|
|
||||||
return (List<String[]>) (values == null ? Collections.emptyList() : values);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Condition getCondition(String conditionClassName,
|
|
||||||
ClassLoader classloader) {
|
|
||||||
Class<?> conditionClass = ClassUtils.resolveClassName(conditionClassName,
|
|
||||||
classloader);
|
|
||||||
return (Condition) BeanUtils.instantiateClass(conditionClass);
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private List<String[]> getConditionClasses(AnnotatedTypeMetadata metadata) {
|
||||||
|
MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(
|
||||||
|
CONDITIONAL_ANNOTATION, true);
|
||||||
|
Object values = attributes == null ? null : attributes.get("value");
|
||||||
|
return (List<String[]>) (values == null ? Collections.emptyList() : values);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Condition getCondition(String conditionClassName,
|
||||||
|
ClassLoader classloader) {
|
||||||
|
Class<?> conditionClass = ClassUtils.resolveClassName(conditionClassName,
|
||||||
|
classloader);
|
||||||
|
return (Condition) BeanUtils.instantiateClass(conditionClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of a {@link ConditionContext}.
|
* Implementation of a {@link ConditionContext}.
|
||||||
*/
|
*/
|
||||||
@@ -144,18 +133,24 @@ abstract class ConditionEvaluator {
|
|||||||
|
|
||||||
private Environment environment;
|
private Environment environment;
|
||||||
|
|
||||||
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
private ClassLoader classLoader;
|
||||||
|
|
||||||
|
private ResourceLoader resourceLoader;
|
||||||
|
|
||||||
|
|
||||||
public ConditionContextImpl(BeanDefinitionRegistry registry,
|
public ConditionContextImpl(BeanDefinitionRegistry registry,
|
||||||
Environment environment) {
|
Environment environment, ApplicationContext applicationContext,
|
||||||
|
ClassLoader classLoader, ResourceLoader resourceLoader) {
|
||||||
this.registry = registry;
|
this.registry = registry;
|
||||||
this.beanFactory = deduceBeanFactory(registry);
|
this.beanFactory = deduceBeanFactory(registry);
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
if (this.environment == null) {
|
this.applicationContext = applicationContext;
|
||||||
this.environment = deduceEnvironment(registry);
|
this.classLoader = classLoader;
|
||||||
}
|
this.resourceLoader = resourceLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private ConfigurableListableBeanFactory deduceBeanFactory(Object source) {
|
private ConfigurableListableBeanFactory deduceBeanFactory(Object source) {
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -169,24 +164,26 @@ abstract class ConditionEvaluator {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Environment deduceEnvironment(BeanDefinitionRegistry registry) {
|
@Override
|
||||||
if (registry == null) {
|
public BeanDefinitionRegistry getRegistry() {
|
||||||
return null;
|
if (this.registry != null) {
|
||||||
|
return this.registry;
|
||||||
}
|
}
|
||||||
if (registry instanceof EnvironmentCapable) {
|
if(getBeanFactory() != null && getBeanFactory() instanceof BeanDefinitionRegistry) {
|
||||||
return ((EnvironmentCapable) registry).getEnvironment();
|
return (BeanDefinitionRegistry) getBeanFactory();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public BeanDefinitionRegistry getRegistry() {
|
|
||||||
return this.registry;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Environment getEnvironment() {
|
public Environment getEnvironment() {
|
||||||
return this.environment;
|
if (this.environment != null) {
|
||||||
|
return this.environment;
|
||||||
|
}
|
||||||
|
if (getRegistry() != null && getRegistry() instanceof EnvironmentCapable) {
|
||||||
|
return ((EnvironmentCapable) getRegistry()).getEnvironment();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -197,6 +194,9 @@ abstract class ConditionEvaluator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResourceLoader getResourceLoader() {
|
public ResourceLoader getResourceLoader() {
|
||||||
|
if (this.resourceLoader != null) {
|
||||||
|
return this.resourceLoader;
|
||||||
|
}
|
||||||
if (registry instanceof ResourceLoader) {
|
if (registry instanceof ResourceLoader) {
|
||||||
return (ResourceLoader) registry;
|
return (ResourceLoader) registry;
|
||||||
}
|
}
|
||||||
@@ -205,8 +205,24 @@ abstract class ConditionEvaluator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClassLoader getClassLoader() {
|
public ClassLoader getClassLoader() {
|
||||||
ResourceLoader resourceLoader = getResourceLoader();
|
if (this.classLoader != null) {
|
||||||
return (resourceLoader == null ? null : resourceLoader.getClassLoader());
|
return this.classLoader;
|
||||||
|
}
|
||||||
|
if (getResourceLoader() != null) {
|
||||||
|
return getResourceLoader().getClassLoader();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApplicationContext getApplicationContext() {
|
||||||
|
if (this.applicationContext != null) {
|
||||||
|
return this.applicationContext;
|
||||||
|
}
|
||||||
|
if (getRegistry() != null && getRegistry() instanceof ApplicationContext) {
|
||||||
|
return (ApplicationContext) getRegistry();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import java.lang.annotation.Target;
|
|||||||
* {@linkplain #value() specified conditions} match.
|
* {@linkplain #value() specified conditions} match.
|
||||||
*
|
*
|
||||||
* <p>A <em>condition</em> is any state that can be determined programmatically
|
* <p>A <em>condition</em> is any state that can be determined programmatically
|
||||||
* immediately before the bean is due to be created (see {@link Condition} for details).
|
* before the bean definition is due to be registered (see {@link Condition} for details).
|
||||||
*
|
*
|
||||||
* <p>The {@code @Conditional} annotation may be used in any of the following ways:
|
* <p>The {@code @Conditional} annotation may be used in any of the following ways:
|
||||||
* <ul>
|
* <ul>
|
||||||
|
|||||||
@@ -219,7 +219,6 @@ final class ConfigurationClass {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
return (this == other || (other instanceof ConfigurationClass &&
|
return (this == other || (other instanceof ConfigurationClass &&
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ import org.springframework.beans.factory.support.BeanDefinitionReader;
|
|||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase;
|
||||||
import org.springframework.core.annotation.AnnotationAttributes;
|
import org.springframework.core.annotation.AnnotationAttributes;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
@@ -85,14 +87,17 @@ class ConfigurationClassBeanDefinitionReader {
|
|||||||
|
|
||||||
private final BeanNameGenerator importBeanNameGenerator;
|
private final BeanNameGenerator importBeanNameGenerator;
|
||||||
|
|
||||||
|
private final ConditionEvaluator conditionEvaluator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link ConfigurationClassBeanDefinitionReader} instance that will be used
|
* Create a new {@link ConfigurationClassBeanDefinitionReader} instance that will be used
|
||||||
* to populate the given {@link BeanDefinitionRegistry}.
|
* to populate the given {@link BeanDefinitionRegistry}.
|
||||||
*/
|
*/
|
||||||
public ConfigurationClassBeanDefinitionReader(
|
public ConfigurationClassBeanDefinitionReader(
|
||||||
BeanDefinitionRegistry registry, SourceExtractor sourceExtractor,
|
BeanDefinitionRegistry registry, ApplicationContext applicationContext,
|
||||||
ProblemReporter problemReporter, MetadataReaderFactory metadataReaderFactory,
|
SourceExtractor sourceExtractor, ProblemReporter problemReporter,
|
||||||
ResourceLoader resourceLoader, Environment environment, BeanNameGenerator importBeanNameGenerator) {
|
MetadataReaderFactory metadataReaderFactory, ResourceLoader resourceLoader,
|
||||||
|
Environment environment, BeanNameGenerator importBeanNameGenerator) {
|
||||||
|
|
||||||
this.registry = registry;
|
this.registry = registry;
|
||||||
this.sourceExtractor = sourceExtractor;
|
this.sourceExtractor = sourceExtractor;
|
||||||
@@ -101,6 +106,8 @@ class ConfigurationClassBeanDefinitionReader {
|
|||||||
this.resourceLoader = resourceLoader;
|
this.resourceLoader = resourceLoader;
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
this.importBeanNameGenerator = importBeanNameGenerator;
|
this.importBeanNameGenerator = importBeanNameGenerator;
|
||||||
|
this.conditionEvaluator = new ConditionEvaluator(registry, environment,
|
||||||
|
applicationContext, null, resourceLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -109,9 +116,9 @@ class ConfigurationClassBeanDefinitionReader {
|
|||||||
* based on its contents.
|
* based on its contents.
|
||||||
*/
|
*/
|
||||||
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
|
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
|
||||||
TrackedConditionEvaluator conditionEvaluator = new TrackedConditionEvaluator();
|
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
|
||||||
for (ConfigurationClass configClass : configurationModel) {
|
for (ConfigurationClass configClass : configurationModel) {
|
||||||
loadBeanDefinitionsForConfigurationClass(configClass, conditionEvaluator);
|
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,9 +127,8 @@ class ConfigurationClassBeanDefinitionReader {
|
|||||||
* class itself, all its {@link Bean} methods
|
* class itself, all its {@link Bean} methods
|
||||||
*/
|
*/
|
||||||
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
|
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
|
||||||
TrackedConditionEvaluator conditionEvaluator) {
|
TrackedConditionEvaluator trackedConditionEvaluator) {
|
||||||
|
if (trackedConditionEvaluator.shouldSkip(configClass)) {
|
||||||
if(conditionEvaluator.shouldSkip(configClass)) {
|
|
||||||
removeBeanDefinition(configClass);
|
removeBeanDefinition(configClass);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -172,8 +178,8 @@ class ConfigurationClassBeanDefinitionReader {
|
|||||||
* with the BeanDefinitionRegistry based on its contents.
|
* with the BeanDefinitionRegistry based on its contents.
|
||||||
*/
|
*/
|
||||||
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
|
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
|
||||||
if (ConditionEvaluator.get(beanMethod.getMetadata(), false).shouldSkip(
|
if (conditionEvaluator.shouldSkip(beanMethod.getMetadata(),
|
||||||
this.registry, this.environment)) {
|
ConfigurationPhase.REGISTER_BEAN)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ConfigurationClass configClass = beanMethod.getConfigurationClass();
|
ConfigurationClass configClass = beanMethod.getConfigurationClass();
|
||||||
@@ -384,6 +390,7 @@ class ConfigurationClassBeanDefinitionReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluate {@Code @Conditional} annotations, tracking results and taking into
|
* Evaluate {@Code @Conditional} annotations, tracking results and taking into
|
||||||
* account 'imported by'.
|
* account 'imported by'.
|
||||||
@@ -402,14 +409,13 @@ class ConfigurationClassBeanDefinitionReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (skip == null) {
|
if (skip == null) {
|
||||||
skip = ConditionEvaluator.get(configClass.getMetadata(), false).shouldSkip(
|
skip = conditionEvaluator.shouldSkip(configClass.getMetadata(),
|
||||||
registry, environment);
|
ConfigurationPhase.REGISTER_BEAN);
|
||||||
}
|
}
|
||||||
this.skipped.put(configClass, skip);
|
this.skipped.put(configClass, skip);
|
||||||
}
|
}
|
||||||
return skip;
|
return skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,8 +46,10 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
|||||||
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
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.ConfigurationCondition.ConfigurationPhase;
|
||||||
import org.springframework.core.NestedIOException;
|
import org.springframework.core.NestedIOException;
|
||||||
import org.springframework.core.annotation.AnnotationAttributes;
|
import org.springframework.core.annotation.AnnotationAttributes;
|
||||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||||
@@ -119,6 +121,8 @@ class ConfigurationClassParser {
|
|||||||
|
|
||||||
private final List<DeferredImportSelectorHolder> deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();
|
private final List<DeferredImportSelectorHolder> deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();
|
||||||
|
|
||||||
|
private final ConditionEvaluator conditionEvaluator;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link ConfigurationClassParser} instance that will be used
|
* Create a new {@link ConfigurationClassParser} instance that will be used
|
||||||
@@ -126,7 +130,8 @@ class ConfigurationClassParser {
|
|||||||
*/
|
*/
|
||||||
public ConfigurationClassParser(MetadataReaderFactory metadataReaderFactory,
|
public ConfigurationClassParser(MetadataReaderFactory metadataReaderFactory,
|
||||||
ProblemReporter problemReporter, Environment environment, ResourceLoader resourceLoader,
|
ProblemReporter problemReporter, Environment environment, ResourceLoader resourceLoader,
|
||||||
BeanNameGenerator componentScanBeanNameGenerator, BeanDefinitionRegistry registry) {
|
BeanNameGenerator componentScanBeanNameGenerator, BeanDefinitionRegistry registry,
|
||||||
|
ApplicationContext applicationContext) {
|
||||||
|
|
||||||
this.metadataReaderFactory = metadataReaderFactory;
|
this.metadataReaderFactory = metadataReaderFactory;
|
||||||
this.problemReporter = problemReporter;
|
this.problemReporter = problemReporter;
|
||||||
@@ -135,6 +140,8 @@ class ConfigurationClassParser {
|
|||||||
this.registry = registry;
|
this.registry = registry;
|
||||||
this.componentScanParser = new ComponentScanAnnotationParser(
|
this.componentScanParser = new ComponentScanAnnotationParser(
|
||||||
resourceLoader, environment, componentScanBeanNameGenerator, registry);
|
resourceLoader, environment, componentScanBeanNameGenerator, registry);
|
||||||
|
this.conditionEvaluator = new ConditionEvaluator(registry, environment,
|
||||||
|
applicationContext, null, resourceLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -162,7 +169,7 @@ class ConfigurationClassParser {
|
|||||||
* @param beanName may be null, but if populated represents the bean id
|
* @param beanName may be null, but if populated represents the bean id
|
||||||
* (assumes that this configuration class was configured via XML)
|
* (assumes that this configuration class was configured via XML)
|
||||||
*/
|
*/
|
||||||
public void parse(String className, String beanName) throws IOException {
|
protected final void parse(String className, String beanName) throws IOException {
|
||||||
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
|
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
|
||||||
processConfigurationClass(new ConfigurationClass(reader, beanName));
|
processConfigurationClass(new ConfigurationClass(reader, beanName));
|
||||||
}
|
}
|
||||||
@@ -172,13 +179,17 @@ class ConfigurationClassParser {
|
|||||||
* @param clazz the Class to parse
|
* @param clazz the Class to parse
|
||||||
* @param beanName must not be null (as of Spring 3.1.1)
|
* @param beanName must not be null (as of Spring 3.1.1)
|
||||||
*/
|
*/
|
||||||
public void parse(Class<?> clazz, String beanName) throws IOException {
|
protected final void parse(Class<?> clazz, String beanName) throws IOException {
|
||||||
processConfigurationClass(new ConfigurationClass(clazz, beanName));
|
processConfigurationClass(new ConfigurationClass(clazz, beanName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
|
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
|
||||||
|
|
||||||
|
if (conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.configurationClasses.contains(configClass) && configClass.getBeanName() != null) {
|
if (this.configurationClasses.contains(configClass) && configClass.getBeanName() != null) {
|
||||||
// Explicit bean definition found, probably replacing an import.
|
// Explicit bean definition found, probably replacing an import.
|
||||||
// Let's remove the old one and go with the new one.
|
// Let's remove the old one and go with the new one.
|
||||||
@@ -224,15 +235,14 @@ class ConfigurationClassParser {
|
|||||||
AnnotationAttributes componentScan = attributesFor(sourceClass.getMetadata(), ComponentScan.class);
|
AnnotationAttributes componentScan = attributesFor(sourceClass.getMetadata(), ComponentScan.class);
|
||||||
if (componentScan != null) {
|
if (componentScan != null) {
|
||||||
// the config class is annotated with @ComponentScan -> perform the scan immediately
|
// the config class is annotated with @ComponentScan -> perform the scan immediately
|
||||||
if (!ConditionEvaluator.get(configClass.getMetadata(), false).shouldSkip(
|
if (!conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
|
||||||
this.registry, this.environment)) {
|
|
||||||
Set<BeanDefinitionHolder> scannedBeanDefinitions =
|
Set<BeanDefinitionHolder> scannedBeanDefinitions =
|
||||||
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
|
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
|
||||||
|
|
||||||
// check the set of scanned definitions for any further config classes and parse recursively if necessary
|
// check the set of scanned definitions for any further config classes and parse recursively if necessary
|
||||||
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
|
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
|
||||||
if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {
|
if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {
|
||||||
this.parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
|
parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ 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.beans.factory.support.RootBeanDefinition;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextAware;
|
||||||
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.ConfigurationClassParser.ImportRegistry;
|
import org.springframework.context.annotation.ConfigurationClassParser.ImportRegistry;
|
||||||
@@ -85,7 +87,7 @@ import static org.springframework.context.annotation.AnnotationConfigUtils.*;
|
|||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
|
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
|
||||||
ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
|
ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware, ApplicationContextAware {
|
||||||
|
|
||||||
private static final String IMPORT_AWARE_PROCESSOR_BEAN_NAME =
|
private static final String IMPORT_AWARE_PROCESSOR_BEAN_NAME =
|
||||||
ConfigurationClassPostProcessor.class.getName() + ".importAwareProcessor";
|
ConfigurationClassPostProcessor.class.getName() + ".importAwareProcessor";
|
||||||
@@ -102,6 +104,8 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
|||||||
|
|
||||||
private Environment environment;
|
private Environment environment;
|
||||||
|
|
||||||
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
private ResourceLoader resourceLoader = new DefaultResourceLoader();
|
private ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||||
|
|
||||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||||
@@ -130,6 +134,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the {@link SourceExtractor} to use for generated bean definitions
|
* Set the {@link SourceExtractor} to use for generated bean definitions
|
||||||
* that correspond to {@link Bean} factory methods.
|
* that correspond to {@link Bean} factory methods.
|
||||||
@@ -189,6 +194,12 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
|||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setApplicationContext(ApplicationContext applicationContext)
|
||||||
|
throws BeansException {
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||||
Assert.notNull(resourceLoader, "ResourceLoader must not be null");
|
Assert.notNull(resourceLoader, "ResourceLoader must not be null");
|
||||||
@@ -279,7 +290,8 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
|||||||
// Parse each @Configuration class
|
// Parse each @Configuration class
|
||||||
ConfigurationClassParser parser = new ConfigurationClassParser(
|
ConfigurationClassParser parser = new ConfigurationClassParser(
|
||||||
this.metadataReaderFactory, this.problemReporter, this.environment,
|
this.metadataReaderFactory, this.problemReporter, this.environment,
|
||||||
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
|
this.resourceLoader, this.componentScanBeanNameGenerator, registry,
|
||||||
|
this.applicationContext);
|
||||||
parser.parse(configCandidates);
|
parser.parse(configCandidates);
|
||||||
parser.validate();
|
parser.validate();
|
||||||
|
|
||||||
@@ -301,7 +313,8 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
|||||||
// Read the model and create bean definitions based on its content
|
// Read the model and create bean definitions based on its content
|
||||||
if (this.reader == null) {
|
if (this.reader == null) {
|
||||||
this.reader = new ConfigurationClassBeanDefinitionReader(
|
this.reader = new ConfigurationClassBeanDefinitionReader(
|
||||||
registry, this.sourceExtractor, this.problemReporter, this.metadataReaderFactory,
|
registry, this.applicationContext, this.sourceExtractor,
|
||||||
|
this.problemReporter, this.metadataReaderFactory,
|
||||||
this.resourceLoader, this.environment, this.importBeanNameGenerator);
|
this.resourceLoader, this.environment, this.importBeanNameGenerator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link Condition} that offers more fine-grained control when used with
|
||||||
|
* {@code @Configuration}. Allows certain {@link Condition}s to adapt when they match
|
||||||
|
* based on the configuration phase. For example, a condition that checks if a bean has
|
||||||
|
* already been registered might choose to only be evaluated on the
|
||||||
|
* {@link ConfigurationPhase#REGISTER_BEAN REGISTER_BEAN} {@link ConfigurationPhase}.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
*/
|
||||||
|
public interface ConfigurationCondition extends Condition {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link ConfigurationPhase} in which the condition should be evaluated.
|
||||||
|
*/
|
||||||
|
ConfigurationPhase getConfigurationPhase();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The various configuration phases where the condition could be evaluated.
|
||||||
|
*/
|
||||||
|
public static enum ConfigurationPhase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link Condition} should be evaluated as a {@code @Configuration} class is
|
||||||
|
* being parsed.
|
||||||
|
*
|
||||||
|
* <p>If the condition does not match at this point the {@code @Configuration}
|
||||||
|
* class will not be added.
|
||||||
|
*/
|
||||||
|
PARSE_CONFIGURATION,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link Condition} should be evaluated when adding a regular (non
|
||||||
|
* {@code @Configuration}) bean. The condition will not prevent
|
||||||
|
* {@code @Configuration} classes from being added.
|
||||||
|
*
|
||||||
|
* <p>At the time that the condition is evaluated all {@code @Configuration}s
|
||||||
|
* will have been parsed.
|
||||||
|
*/
|
||||||
|
REGISTER_BEAN
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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");
|
* 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.
|
||||||
@@ -41,7 +41,8 @@ public class AsmCircularImportDetectionTests extends AbstractCircularImportDetec
|
|||||||
new StandardEnvironment(),
|
new StandardEnvironment(),
|
||||||
new DefaultResourceLoader(),
|
new DefaultResourceLoader(),
|
||||||
new AnnotationBeanNameGenerator(),
|
new AnnotationBeanNameGenerator(),
|
||||||
new DefaultListableBeanFactory());
|
new DefaultListableBeanFactory(),
|
||||||
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -16,12 +16,6 @@
|
|||||||
|
|
||||||
package org.springframework.context.annotation;
|
package org.springframework.context.annotation;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
@@ -32,15 +26,22 @@ import org.junit.Rule;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.ExpectedException;
|
import org.junit.rules.ExpectedException;
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.core.annotation.AnnotationAttributes;
|
import org.springframework.core.annotation.AnnotationAttributes;
|
||||||
|
import org.springframework.core.io.DefaultResourceLoader;
|
||||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||||
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link Conditional} beans.
|
* Tests for {@link Conditional} beans.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("resource")
|
||||||
public class ConfigurationClassWithConditionTests {
|
public class ConfigurationClassWithConditionTests {
|
||||||
|
|
||||||
private final AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
private final AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
@@ -110,6 +111,32 @@ public class ConfigurationClassWithConditionTests {
|
|||||||
assertNull(ctx.getBean(ExampleBean.class));
|
assertNull(ctx.getBean(ExampleBean.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void importsNotCreated() throws Exception {
|
||||||
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
|
ctx.register(ImportsNotCreated.class);
|
||||||
|
ctx.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void importsNotLoaded() throws Exception {
|
||||||
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
|
ctx.register(ImportsNotLoaded.class);
|
||||||
|
ctx.refresh();
|
||||||
|
assertThat(ctx.containsBeanDefinition("a"), equalTo(false));
|
||||||
|
assertThat(ctx.containsBeanDefinition("b"), equalTo(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void sensibleConditionContext() throws Exception {
|
||||||
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
|
ctx.setResourceLoader(new DefaultResourceLoader());
|
||||||
|
ctx.setClassLoader(getClass().getClassLoader());
|
||||||
|
ctx.register(SensibleConditionContext.class);
|
||||||
|
ctx.refresh();
|
||||||
|
assertThat(ctx.getBean(ExampleBean.class), instanceOf(ExampleBean.class));
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
static class BeanOneConfiguration {
|
static class BeanOneConfiguration {
|
||||||
@Bean
|
@Bean
|
||||||
@@ -166,7 +193,12 @@ public class ConfigurationClassWithConditionTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class HasBeanOneCondition implements Condition {
|
static class HasBeanOneCondition implements ConfigurationCondition {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigurationPhase getConfigurationPhase() {
|
||||||
|
return ConfigurationPhase.REGISTER_BEAN;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||||
@@ -206,6 +238,112 @@ public class ConfigurationClassWithConditionTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Never
|
||||||
|
@Import({ ConfigurationNotCreated.class, RegistrarNotCreated.class, ImportSelectorNotCreated.class })
|
||||||
|
static class ImportsNotCreated {
|
||||||
|
static {
|
||||||
|
if (true) throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class ConfigurationNotCreated {
|
||||||
|
static {
|
||||||
|
if (true) throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class RegistrarNotCreated implements ImportBeanDefinitionRegistrar {
|
||||||
|
static {
|
||||||
|
if (true) throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
|
||||||
|
BeanDefinitionRegistry registry) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ImportSelectorNotCreated implements ImportSelector {
|
||||||
|
|
||||||
|
static {
|
||||||
|
if (true) throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
|
||||||
|
return new String[] {};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Never
|
||||||
|
@Import({ ConfigurationNotLoaded.class, RegistrarNotLoaded.class, ImportSelectorNotLoaded.class })
|
||||||
|
static class ImportsNotLoaded {
|
||||||
|
static {
|
||||||
|
if (true) throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class ConfigurationNotLoaded {
|
||||||
|
@Bean
|
||||||
|
public String a() {
|
||||||
|
return "a";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class RegistrarNotLoaded implements ImportBeanDefinitionRegistrar {
|
||||||
|
@Override
|
||||||
|
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
|
||||||
|
BeanDefinitionRegistry registry) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ImportSelectorNotLoaded implements ImportSelector {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
|
||||||
|
return new String[] { SelectedConfigurationNotLoaded.class.getName() };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class SelectedConfigurationNotLoaded {
|
||||||
|
@Bean
|
||||||
|
public String b() {
|
||||||
|
return "b";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Conditional(SensibleConditionContextCondition.class)
|
||||||
|
static class SensibleConditionContext {
|
||||||
|
@Bean
|
||||||
|
ExampleBean exampleBean() {
|
||||||
|
return new ExampleBean();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SensibleConditionContextCondition implements Condition {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||||
|
assertThat(context.getApplicationContext(), notNullValue());
|
||||||
|
assertThat(context.getBeanFactory(), notNullValue());
|
||||||
|
assertThat(context.getClassLoader(), notNullValue());
|
||||||
|
assertThat(context.getEnvironment(), notNullValue());
|
||||||
|
assertThat(context.getRegistry(), notNullValue());
|
||||||
|
assertThat(context.getResourceLoader(), notNullValue());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static class ExampleBean {
|
static class ExampleBean {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user