ConfigurationClassParser enforces @Bean declaration order through ASM metadata

Issue: SPR-14505
(cherry picked from commit 3295a4e)
This commit is contained in:
Juergen Hoeller 2016-12-23 20:29:12 +01:00
parent 505480cf63
commit 4a84ee07be
2 changed files with 31 additions and 8 deletions

View File

@ -291,7 +291,7 @@ class ConfigurationClassParser {
}
// Process individual @Bean methods
Set<MethodMetadata> beanMethods = sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName());
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
@ -341,7 +341,7 @@ class ConfigurationClassParser {
*/
private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
for (SourceClass ifc : sourceClass.getInterfaces()) {
Set<MethodMetadata> beanMethods = ifc.getMetadata().getAnnotatedMethods(Bean.class.getName());
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);
for (MethodMetadata methodMetadata : beanMethods) {
if (!methodMetadata.isAbstract()) {
// A default method or other concrete method on a Java 8+ interface...
@ -352,6 +352,29 @@ class ConfigurationClassParser {
}
}
/**
* Retrieve the metadata for all <code>@Bean</code> methods.
*/
private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {
AnnotationMetadata original = sourceClass.getMetadata();
Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
// Try reading the class file via ASM for deterministic declaration order...
// Unfortunately, the JVM's standard reflection returns methods in arbitrary
// order, even between different runs of the same application on the same JVM.
try {
AnnotationMetadata asm =
this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
beanMethods = asm.getAnnotatedMethods(Bean.class.getName());
}
catch (IOException ex) {
logger.debug("Failed to read class file via ASM for determining @Bean method order", ex);
// No worries, let's continue with the reflection metadata we started with...
}
}
return beanMethods;
}
/**
* Process the given <code>@PropertySource</code> annotation metadata.
* @param propertySource metadata for the <code>@PropertySource</code> annotation found
@ -588,7 +611,7 @@ class ConfigurationClassParser {
if (metadata instanceof StandardAnnotationMetadata) {
return asSourceClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
}
return asSourceClass(configurationClass.getMetadata().getClassName());
return asSourceClass(metadata.getClassName());
}
/**

View File

@ -1281,15 +1281,15 @@ public class ConfigurationClassPostProcessorTests {
@Configuration
static class FooBarConfiguration {
@Bean @DependsOn("bar")
public FooImpl foo() {
return new FooImpl();
}
@Bean
public BarInterface bar() {
return new BarImpl();
}
@Bean
public FooImpl foo() {
return new FooImpl();
}
}
@Configuration