Revised @Bean processing rules

@Bean method metadata is always being picked from the most concrete subclass; @Bean method overloads are allowed within the same config class as well; and @Bean overrides and overloads work with 'allowBeanDefinitionOverriding'=false now.

Issue: SPR-10992
Issue: SPR-11025
This commit is contained in:
Juergen Hoeller
2013-11-04 23:34:00 +01:00
parent e146e53d9b
commit 935bd25b09
3 changed files with 92 additions and 73 deletions

View File

@@ -17,7 +17,6 @@
package org.springframework.context.annotation;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
@@ -156,8 +155,8 @@ final class ConfigurationClass {
}
/**
* Returns the configuration class that imported this class or {@code null} if
* this configuration was not imported.
* Return the configuration class that imported this class,
* or {@code null} if this configuration was not imported.
* @since 4.0
* @see #isImported()
*/
@@ -182,7 +181,7 @@ final class ConfigurationClass {
}
public Set<ImportBeanDefinitionRegistrar> getImportBeanDefinitionRegistrars() {
return Collections.unmodifiableSet(importBeanDefinitionRegistrars);
return Collections.unmodifiableSet(this.importBeanDefinitionRegistrars);
}
public Map<String, Class<? extends BeanDefinitionReader>> getImportedResources() {
@@ -197,23 +196,6 @@ final class ConfigurationClass {
}
}
// An @Bean method may only be overloaded through inheritance. No single
// @Configuration class may declare two @Bean methods with the same name.
Map<String, Integer> methodNameCounts = new HashMap<String, Integer>();
for (BeanMethod beanMethod : this.beanMethods) {
String fqMethodName = beanMethod.getFullyQualifiedMethodName();
Integer currentCount = methodNameCounts.get(fqMethodName);
int newCount = (currentCount != null ? currentCount + 1 : 1);
methodNameCounts.put(fqMethodName, newCount);
}
for (String fqMethodName : methodNameCounts.keySet()) {
int count = methodNameCounts.get(fqMethodName);
if (count > 1) {
String shortMethodName = ConfigurationMethod.getShortMethodName(fqMethodName);
problemReporter.error(new BeanMethodOverloadingProblem(shortMethodName, count));
}
}
for (BeanMethod beanMethod : this.beanMethods) {
beanMethod.validate(problemReporter);
}
@@ -232,7 +214,7 @@ final class ConfigurationClass {
@Override
public String toString() {
return String.format("[ConfigurationClass:beanName=%s,resource=%s]", this.beanName, this.resource);
return "ConfigurationClass:beanName=" + this.beanName + ",resource=" + this.resource;
}
@@ -247,17 +229,4 @@ final class ConfigurationClass {
}
}
/**
* Bean methods on configuration classes may only be overloaded through inheritance.
*/
private class BeanMethodOverloadingProblem extends Problem {
public BeanMethodOverloadingProblem(String methodName, int count) {
super(String.format("@Configuration class '%s' has %s overloaded @Bean methods named '%s'. " +
"Only one @Bean method of a given name is allowed within each @Configuration class.",
getSimpleName(), count, methodName), new Location(getResource(), getMetadata()));
}
}
}

View File

@@ -174,6 +174,7 @@ class ConfigurationClassBeanDefinitionReader {
if (this.conditionEvaluator.shouldSkip(beanMethod.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
return;
}
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
@@ -258,9 +259,12 @@ class ConfigurationClassBeanDefinitionReader {
BeanDefinition existingBeanDef = this.registry.getBeanDefinition(beanName);
// Is the existing bean definition one that was created from a configuration class?
// -> allow the current bean method to override, since both are at second-pass level
// -> allow the current bean method to override, since both are at second-pass level.
// However, if the bean method is an overloaded case on the same configuration class,
// preserve the existing bean definition.
if (existingBeanDef instanceof ConfigurationClassBeanDefinition) {
return false;
ConfigurationClassBeanDefinition ccbd = (ConfigurationClassBeanDefinition) existingBeanDef;
return (ccbd.getMetadata().getClassName().equals(beanMethod.getConfigurationClass().getMetadata().getClassName()));
}
// Has the existing bean definition bean marked as a framework-generated bean?