Allow BFPP to modify database initialization ordering
Fixes gh-26899
This commit is contained in:
@@ -34,6 +34,7 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.boot.util.Instantiator;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
@@ -84,7 +85,7 @@ public class DatabaseInitializationDependencyConfigurer implements ImportBeanDef
|
||||
* {@link BeanFactoryPostProcessor} used to configure database initialization
|
||||
* dependency relationships.
|
||||
*/
|
||||
static class DependsOnDatabaseInitializationPostProcessor implements BeanFactoryPostProcessor {
|
||||
static class DependsOnDatabaseInitializationPostProcessor implements BeanFactoryPostProcessor, Ordered {
|
||||
|
||||
private final Environment environment;
|
||||
|
||||
@@ -92,6 +93,11 @@ public class DatabaseInitializationDependencyConfigurer implements ImportBeanDef
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
|
||||
Set<String> initializerBeanNames = detectInitializerBeanNames(beanFactory);
|
||||
|
||||
@@ -24,7 +24,10 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
@@ -35,9 +38,11 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
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.support.BeanDefinitionBuilder;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.Ordered;
|
||||
@@ -70,6 +75,30 @@ class DatabaseInitializationDependencyConfigurerTests {
|
||||
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
|
||||
void whenDetectorsAreCreatedThenTheEnvironmentCanBeInjected() {
|
||||
performDetection(Arrays.asList(ConstructorInjectionDatabaseInitializerDetector.class,
|
||||
@@ -77,6 +106,7 @@ class DatabaseInitializationDependencyConfigurerTests {
|
||||
BeanDefinition alpha = BeanDefinitionBuilder.genericBeanDefinition(String.class)
|
||||
.getBeanDefinition();
|
||||
context.registerBeanDefinition("alpha", alpha);
|
||||
context.register(DependencyConfigurerConfiguration.class);
|
||||
context.refresh();
|
||||
assertThat(ConstructorInjectionDatabaseInitializerDetector.environment).isEqualTo(this.environment);
|
||||
assertThat(ConstructorInjectionDependsOnDatabaseInitializationDetector.environment)
|
||||
@@ -96,6 +126,7 @@ class DatabaseInitializationDependencyConfigurerTests {
|
||||
.willReturn(Collections.singleton("alpha"));
|
||||
given(MockedDependsOnDatabaseInitializationDetector.instance.detect(context.getBeanFactory()))
|
||||
.willReturn(Collections.singleton("bravo"));
|
||||
context.register(DependencyConfigurerConfiguration.class);
|
||||
context.refresh();
|
||||
assertThat(alpha.getAttribute(DatabaseInitializerDetector.class.getName()))
|
||||
.isEqualTo(MockDatabaseInitializerDetector.class.getName());
|
||||
@@ -123,6 +154,7 @@ class DatabaseInitializationDependencyConfigurerTests {
|
||||
context.registerBeanDefinition("alpha", alpha);
|
||||
context.registerBeanDefinition("bravo", bravo);
|
||||
context.registerBeanDefinition("charlie", charlie);
|
||||
context.register(DependencyConfigurerConfiguration.class);
|
||||
context.refresh();
|
||||
assertThat(charlie.getDependsOn()).containsExactly("alpha", "bravo");
|
||||
assertThat(bravo.getDependsOn()).containsExactly("alpha");
|
||||
@@ -137,7 +169,6 @@ class DatabaseInitializationDependencyConfigurerTests {
|
||||
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
|
||||
context.setEnvironment(this.environment);
|
||||
context.setClassLoader(detectorSpringFactories);
|
||||
context.register(DependencyConfigurerConfiguration.class);
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user