ConfigurationClassParser enforces @Bean declaration order through ASM metadata
Issue: SPR-14505
This commit is contained in:
parent
8147c112f5
commit
3295a4e6ef
|
|
@ -291,7 +291,7 @@ class ConfigurationClassParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process individual @Bean methods
|
// Process individual @Bean methods
|
||||||
Set<MethodMetadata> beanMethods = sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName());
|
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
|
||||||
for (MethodMetadata methodMetadata : beanMethods) {
|
for (MethodMetadata methodMetadata : beanMethods) {
|
||||||
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
|
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
|
||||||
}
|
}
|
||||||
|
|
@ -341,7 +341,7 @@ class ConfigurationClassParser {
|
||||||
*/
|
*/
|
||||||
private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
|
private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
|
||||||
for (SourceClass ifc : sourceClass.getInterfaces()) {
|
for (SourceClass ifc : sourceClass.getInterfaces()) {
|
||||||
Set<MethodMetadata> beanMethods = ifc.getMetadata().getAnnotatedMethods(Bean.class.getName());
|
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);
|
||||||
for (MethodMetadata methodMetadata : beanMethods) {
|
for (MethodMetadata methodMetadata : beanMethods) {
|
||||||
if (!methodMetadata.isAbstract()) {
|
if (!methodMetadata.isAbstract()) {
|
||||||
// A default method or other concrete method on a Java 8+ interface...
|
// 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.
|
* Process the given <code>@PropertySource</code> annotation metadata.
|
||||||
* @param propertySource metadata for the <code>@PropertySource</code> annotation found
|
* @param propertySource metadata for the <code>@PropertySource</code> annotation found
|
||||||
|
|
@ -588,7 +611,7 @@ class ConfigurationClassParser {
|
||||||
if (metadata instanceof StandardAnnotationMetadata) {
|
if (metadata instanceof StandardAnnotationMetadata) {
|
||||||
return asSourceClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
|
return asSourceClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
|
||||||
}
|
}
|
||||||
return asSourceClass(configurationClass.getMetadata().getClassName());
|
return asSourceClass(metadata.getClassName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1281,15 +1281,15 @@ public class ConfigurationClassPostProcessorTests {
|
||||||
@Configuration
|
@Configuration
|
||||||
static class FooBarConfiguration {
|
static class FooBarConfiguration {
|
||||||
|
|
||||||
@Bean @DependsOn("bar")
|
|
||||||
public FooImpl foo() {
|
|
||||||
return new FooImpl();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public BarInterface bar() {
|
public BarInterface bar() {
|
||||||
return new BarImpl();
|
return new BarImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public FooImpl foo() {
|
||||||
|
return new FooImpl();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue