Merge branch '2.5.x'

Closes gh-26951
pull/26954/head
Andy Wilkinson 3 years ago
commit b1c04e91d7

@ -34,6 +34,7 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.util.Instantiator; import org.springframework.boot.util.Instantiator;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.Ordered;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.core.io.support.SpringFactoriesLoader; import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.AnnotationMetadata;
@ -84,7 +85,7 @@ public class DatabaseInitializationDependencyConfigurer implements ImportBeanDef
* {@link BeanFactoryPostProcessor} used to configure database initialization * {@link BeanFactoryPostProcessor} used to configure database initialization
* dependency relationships. * dependency relationships.
*/ */
static class DependsOnDatabaseInitializationPostProcessor implements BeanFactoryPostProcessor { static class DependsOnDatabaseInitializationPostProcessor implements BeanFactoryPostProcessor, Ordered {
private final Environment environment; private final Environment environment;
@ -92,6 +93,11 @@ public class DatabaseInitializationDependencyConfigurer implements ImportBeanDef
this.environment = environment; this.environment = environment;
} }
@Override
public int getOrder() {
return 0;
}
@Override @Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
Set<String> initializerBeanNames = detectInitializerBeanNames(beanFactory); Set<String> initializerBeanNames = detectInitializerBeanNames(beanFactory);

@ -24,7 +24,10 @@ import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -35,9 +38,11 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
@ -70,6 +75,30 @@ class DatabaseInitializationDependencyConfigurerTests {
MockedDependsOnDatabaseInitializationDetector.instance); MockedDependsOnDatabaseInitializationDetector.instance);
} }
@Test
void beanFactoryPostProcessorHasOrderAllowingSubsequentPostProcessorsToFineTuneDependencies() {
performDetection(Arrays.asList(MockDatabaseInitializerDetector.class,
MockedDependsOnDatabaseInitializationDetector.class), (context) -> {
BeanDefinition alpha = BeanDefinitionBuilder.genericBeanDefinition(String.class)
.getBeanDefinition();
BeanDefinition bravo = BeanDefinitionBuilder.genericBeanDefinition(String.class)
.getBeanDefinition();
context.register(DependsOnCaptor.class);
context.register(DependencyConfigurerConfiguration.class);
context.registerBeanDefinition("alpha", alpha);
context.registerBeanDefinition("bravo", bravo);
given(MockDatabaseInitializerDetector.instance.detect(context.getBeanFactory()))
.willReturn(Collections.singleton("alpha"));
given(MockedDependsOnDatabaseInitializationDetector.instance.detect(context.getBeanFactory()))
.willReturn(Collections.singleton("bravo"));
context.refresh();
assertThat(DependsOnCaptor.dependsOn).hasEntrySatisfying("bravo",
(dependencies) -> assertThat(dependencies).containsExactly("alpha"));
assertThat(DependsOnCaptor.dependsOn).hasEntrySatisfying("alpha",
(dependencies) -> assertThat(dependencies).isEmpty());
});
}
@Test @Test
void whenDetectorsAreCreatedThenTheEnvironmentCanBeInjected() { void whenDetectorsAreCreatedThenTheEnvironmentCanBeInjected() {
performDetection(Arrays.asList(ConstructorInjectionDatabaseInitializerDetector.class, performDetection(Arrays.asList(ConstructorInjectionDatabaseInitializerDetector.class,
@ -77,6 +106,7 @@ class DatabaseInitializationDependencyConfigurerTests {
BeanDefinition alpha = BeanDefinitionBuilder.genericBeanDefinition(String.class) BeanDefinition alpha = BeanDefinitionBuilder.genericBeanDefinition(String.class)
.getBeanDefinition(); .getBeanDefinition();
context.registerBeanDefinition("alpha", alpha); context.registerBeanDefinition("alpha", alpha);
context.register(DependencyConfigurerConfiguration.class);
context.refresh(); context.refresh();
assertThat(ConstructorInjectionDatabaseInitializerDetector.environment).isEqualTo(this.environment); assertThat(ConstructorInjectionDatabaseInitializerDetector.environment).isEqualTo(this.environment);
assertThat(ConstructorInjectionDependsOnDatabaseInitializationDetector.environment) assertThat(ConstructorInjectionDependsOnDatabaseInitializationDetector.environment)
@ -96,6 +126,7 @@ class DatabaseInitializationDependencyConfigurerTests {
.willReturn(Collections.singleton("alpha")); .willReturn(Collections.singleton("alpha"));
given(MockedDependsOnDatabaseInitializationDetector.instance.detect(context.getBeanFactory())) given(MockedDependsOnDatabaseInitializationDetector.instance.detect(context.getBeanFactory()))
.willReturn(Collections.singleton("bravo")); .willReturn(Collections.singleton("bravo"));
context.register(DependencyConfigurerConfiguration.class);
context.refresh(); context.refresh();
assertThat(alpha.getAttribute(DatabaseInitializerDetector.class.getName())) assertThat(alpha.getAttribute(DatabaseInitializerDetector.class.getName()))
.isEqualTo(MockDatabaseInitializerDetector.class.getName()); .isEqualTo(MockDatabaseInitializerDetector.class.getName());
@ -123,6 +154,7 @@ class DatabaseInitializationDependencyConfigurerTests {
context.registerBeanDefinition("alpha", alpha); context.registerBeanDefinition("alpha", alpha);
context.registerBeanDefinition("bravo", bravo); context.registerBeanDefinition("bravo", bravo);
context.registerBeanDefinition("charlie", charlie); context.registerBeanDefinition("charlie", charlie);
context.register(DependencyConfigurerConfiguration.class);
context.refresh(); context.refresh();
assertThat(charlie.getDependsOn()).containsExactly("alpha", "bravo"); assertThat(charlie.getDependsOn()).containsExactly("alpha", "bravo");
assertThat(bravo.getDependsOn()).containsExactly("alpha"); assertThat(bravo.getDependsOn()).containsExactly("alpha");
@ -137,7 +169,6 @@ class DatabaseInitializationDependencyConfigurerTests {
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) { try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
context.setEnvironment(this.environment); context.setEnvironment(this.environment);
context.setClassLoader(detectorSpringFactories); context.setClassLoader(detectorSpringFactories);
context.register(DependencyConfigurerConfiguration.class);
contextCallback.accept(context); contextCallback.accept(context);
} }
} }
@ -270,4 +301,28 @@ class DatabaseInitializationDependencyConfigurerTests {
} }
@Configuration(proxyBeanMethods = false)
static class DependsOnCaptor {
static final Map<String, List<String>> dependsOn = new HashMap<>();
@Bean
static BeanFactoryPostProcessor dependsOnCapturingPostProcessor() {
return (beanFactory) -> {
dependsOn.clear();
for (String name : beanFactory.getBeanDefinitionNames()) {
storeDependsOn(name, beanFactory);
}
};
}
private static void storeDependsOn(String name, ConfigurableListableBeanFactory beanFactory) {
String[] dependsOn = beanFactory.getBeanDefinition(name).getDependsOn();
if (dependsOn != null) {
DependsOnCaptor.dependsOn.put(name, Arrays.asList(dependsOn));
}
}
}
} }

Loading…
Cancel
Save