Support for @Order on nested configuration classes
Issue: SPR-15384
This commit is contained in:
parent
e9627a10c7
commit
917207b7ae
|
@ -50,6 +50,8 @@ 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.annotation.ConfigurationCondition.ConfigurationPhase;
|
import org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase;
|
||||||
import org.springframework.core.NestedIOException;
|
import org.springframework.core.NestedIOException;
|
||||||
|
import org.springframework.core.OrderComparator;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.annotation.AnnotationAttributes;
|
import org.springframework.core.annotation.AnnotationAttributes;
|
||||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||||
import org.springframework.core.env.CompositePropertySource;
|
import org.springframework.core.env.CompositePropertySource;
|
||||||
|
@ -330,16 +332,24 @@ class ConfigurationClassParser {
|
||||||
* Register member (nested) classes that happen to be configuration classes themselves.
|
* Register member (nested) classes that happen to be configuration classes themselves.
|
||||||
*/
|
*/
|
||||||
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
|
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
|
||||||
for (SourceClass memberClass : sourceClass.getMemberClasses()) {
|
Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
|
||||||
if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
|
if (!memberClasses.isEmpty()) {
|
||||||
!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
|
List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
|
||||||
|
for (SourceClass memberClass : memberClasses) {
|
||||||
|
if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
|
||||||
|
!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
|
||||||
|
candidates.add(memberClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OrderComparator.sort(candidates);
|
||||||
|
for (SourceClass candidate : candidates) {
|
||||||
if (this.importStack.contains(configClass)) {
|
if (this.importStack.contains(configClass)) {
|
||||||
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
|
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.importStack.push(configClass);
|
this.importStack.push(configClass);
|
||||||
try {
|
try {
|
||||||
processConfigurationClass(memberClass.asConfigClass(configClass));
|
processConfigurationClass(candidate.asConfigClass(configClass));
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
this.importStack.pop();
|
this.importStack.pop();
|
||||||
|
@ -747,7 +757,7 @@ class ConfigurationClassParser {
|
||||||
* Simple wrapper that allows annotated source classes to be dealt with
|
* Simple wrapper that allows annotated source classes to be dealt with
|
||||||
* in a uniform manner, regardless of how they are loaded.
|
* in a uniform manner, regardless of how they are loaded.
|
||||||
*/
|
*/
|
||||||
private class SourceClass {
|
private class SourceClass implements Ordered {
|
||||||
|
|
||||||
private final Object source; // Class or MetadataReader
|
private final Object source; // Class or MetadataReader
|
||||||
|
|
||||||
|
@ -767,6 +777,12 @@ class ConfigurationClassParser {
|
||||||
return this.metadata;
|
return this.metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
Integer order = ConfigurationClassUtils.getOrder(this.metadata);
|
||||||
|
return (order != null ? order : Ordered.LOWEST_PRECEDENCE);
|
||||||
|
}
|
||||||
|
|
||||||
public Class<?> loadClass() throws ClassNotFoundException {
|
public Class<?> loadClass() throws ClassNotFoundException {
|
||||||
if (this.source instanceof Class) {
|
if (this.source instanceof Class) {
|
||||||
return (Class<?>) this.source;
|
return (Class<?>) this.source;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2017 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.
|
||||||
|
@ -119,9 +119,9 @@ abstract class ConfigurationClassUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
// It's a full or lite configuration candidate... Let's determine the order value, if any.
|
// It's a full or lite configuration candidate... Let's determine the order value, if any.
|
||||||
Map<String, Object> orderAttributes = metadata.getAnnotationAttributes(Order.class.getName());
|
Integer order = getOrder(metadata);
|
||||||
if (orderAttributes != null) {
|
if (order != null) {
|
||||||
beanDef.setAttribute(ORDER_ATTRIBUTE, orderAttributes.get(AnnotationUtils.VALUE));
|
beanDef.setAttribute(ORDER_ATTRIBUTE, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -198,6 +198,18 @@ abstract class ConfigurationClassUtils {
|
||||||
return CONFIGURATION_CLASS_LITE.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
|
return CONFIGURATION_CLASS_LITE.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the order for the given configuration class metadata.
|
||||||
|
* @param metadata the metadata of the annotated class
|
||||||
|
* @return the {@link @Order} annotation value on the configuration class,
|
||||||
|
* or {@link Ordered#LOWEST_PRECEDENCE} if none declared
|
||||||
|
* @since 5.0
|
||||||
|
*/
|
||||||
|
public static Integer getOrder(AnnotationMetadata metadata) {
|
||||||
|
Map<String, Object> orderAttributes = metadata.getAnnotationAttributes(Order.class.getName());
|
||||||
|
return (orderAttributes != null ? ((Integer) orderAttributes.get(AnnotationUtils.VALUE)) : null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine the order for the given configuration class bean definition,
|
* Determine the order for the given configuration class bean definition,
|
||||||
* as set by {@link #checkConfigurationClassCandidate}.
|
* as set by {@link #checkConfigurationClassCandidate}.
|
||||||
|
|
|
@ -348,6 +348,18 @@ public class ConfigurationClassPostProcessorTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nestedConfigurationClassesProcessedInCorrectOrder() {
|
||||||
|
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(ConfigWithOrderedNestedClasses.class));
|
||||||
|
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
||||||
|
pp.postProcessBeanFactory(beanFactory);
|
||||||
|
|
||||||
|
Foo foo = beanFactory.getBean(Foo.class);
|
||||||
|
assertTrue(foo instanceof ExtendedFoo);
|
||||||
|
Bar bar = beanFactory.getBean(Bar.class);
|
||||||
|
assertSame(foo, bar.foo);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void scopedProxyTargetMarkedAsNonAutowireCandidate() {
|
public void scopedProxyTargetMarkedAsNonAutowireCandidate() {
|
||||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||||
|
@ -833,6 +845,36 @@ public class ConfigurationClassPostProcessorTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class ConfigWithOrderedNestedClasses {
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Order(1)
|
||||||
|
static class SingletonBeanConfig {
|
||||||
|
|
||||||
|
public @Bean Foo foo() {
|
||||||
|
return new Foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Bean Bar bar() {
|
||||||
|
return new Bar(foo());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Order(2)
|
||||||
|
static class OverridingSingletonBeanConfig {
|
||||||
|
|
||||||
|
public @Bean ExtendedFoo foo() {
|
||||||
|
return new ExtendedFoo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Bean Bar bar() {
|
||||||
|
return new Bar(foo());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static class Foo {
|
static class Foo {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue