@Configuration classes get processed according to their @Order (if applicable)

Issue: SPR-12657
This commit is contained in:
Juergen Hoeller
2015-03-13 18:18:21 +01:00
parent 9d497cbd98
commit f5b4e18209
3 changed files with 97 additions and 8 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -17,10 +17,14 @@
package org.springframework.context.annotation;
import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -264,7 +268,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
* {@link Configuration} classes.
*/
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
Set<BeanDefinitionHolder> configCandidates = new LinkedHashSet<BeanDefinitionHolder>();
List<BeanDefinitionHolder> configCandidates = new ArrayList<BeanDefinitionHolder>();
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
@@ -285,6 +289,16 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
return;
}
// Sort by previously determined @Order value, if applicable
Collections.sort(configCandidates, new Comparator<BeanDefinitionHolder>() {
@Override
public int compare(BeanDefinitionHolder bd1, BeanDefinitionHolder bd2) {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
}
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry singletonRegistry = null;
if (registry instanceof SingletonBeanRegistry) {
@@ -301,9 +315,10 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<BeanDefinitionHolder>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<ConfigurationClass>(configCandidates.size());
do {
parser.parse(configCandidates);
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<ConfigurationClass>(parser.getConfigurationClasses());
@@ -318,7 +333,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
configCandidates.clear();
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<String>(Arrays.asList(candidateNames));
@@ -331,14 +346,14 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
BeanDefinition beanDef = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(beanDef.getBeanClassName())) {
configCandidates.add(new BeanDefinitionHolder(beanDef, candidateName));
candidates.add(new BeanDefinitionHolder(beanDef, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!configCandidates.isEmpty());
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (singletonRegistry != null) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -18,6 +18,7 @@ package org.springframework.context.annotation;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
@@ -27,6 +28,9 @@ import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.core.Conventions;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
@@ -49,6 +53,9 @@ abstract class ConfigurationClassUtils {
private static final String CONFIGURATION_CLASS_ATTRIBUTE =
Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "configurationClass");
private static final String ORDER_ATTRIBUTE =
Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "order");
private static final Log logger = LogFactory.getLog(ConfigurationClassUtils.class);
@@ -101,6 +108,11 @@ abstract class ConfigurationClassUtils {
}
}
Map<String, Object> orderAttributes = metadata.getAnnotationAttributes(Order.class.getName());
if (orderAttributes != null) {
beanDef.setAttribute(ORDER_ATTRIBUTE, orderAttributes.get(AnnotationUtils.VALUE));
}
if (isFullConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
return true;
@@ -173,4 +185,16 @@ abstract class ConfigurationClassUtils {
return CONFIGURATION_CLASS_LITE.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
}
/**
* Determine the order for the given configuration class bean definition,
* as set by {@link #checkConfigurationClassCandidate}.
* @param beanDef the bean definition to check
* @return the {@link @Order} annotation value on the configuration class,
* or {@link Ordered#LOWEST_PRECEDENCE} if none declared
*/
public static int getOrder(BeanDefinition beanDef) {
Integer order = (Integer) beanDef.getAttribute(ORDER_ATTRIBUTE);
return (order != null ? order : Ordered.LOWEST_PRECEDENCE);
}
}