mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-17 08:24:13 +00:00
Replace DeferredBeanRegistrar with implicit ordering semantics
GenericApplicationContext-registered BeanRegistrars are invoked after other programmatic bean definitions. Configuration-imported BeanRegistrars participate in configuration class order and in particular in Boot's auto-configuration ordering. Closes gh-21497
This commit is contained in:
+5
-8
@@ -45,7 +45,6 @@ import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.beans.factory.support.BeanRegistryAdapter;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.context.DeferredBeanRegistrar;
|
||||
import org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.env.Environment;
|
||||
@@ -425,14 +424,12 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
|
||||
private void loadBeanDefinitionsFromBeanRegistrars(MultiValueMap<String, BeanRegistrar> registrars) {
|
||||
registrars.values().forEach(registrarList -> registrarList.forEach(registrar -> {
|
||||
if (!(registrar instanceof DeferredBeanRegistrar)) {
|
||||
if (!(this.registry instanceof ListableBeanFactory beanFactory)) {
|
||||
throw new IllegalStateException("Cannot support bean registrars since " +
|
||||
this.registry.getClass().getName() + " does not implement ListableBeanFactory");
|
||||
}
|
||||
registrar.register(new BeanRegistryAdapter(
|
||||
this.registry, beanFactory, this.environment, registrar.getClass()), this.environment);
|
||||
if (!(this.registry instanceof ListableBeanFactory beanFactory)) {
|
||||
throw new IllegalStateException("Cannot support bean registrars since " +
|
||||
this.registry.getClass().getName() + " does not implement ListableBeanFactory");
|
||||
}
|
||||
registrar.register(new BeanRegistryAdapter(
|
||||
this.registry, beanFactory, this.environment, registrar.getClass()), this.environment);
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
+1
-22
@@ -94,13 +94,11 @@ import org.springframework.beans.factory.support.RegisteredBean;
|
||||
import org.springframework.beans.factory.support.RegisteredBean.InstantiationDescriptor;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.ApplicationStartupAware;
|
||||
import org.springframework.context.DeferredBeanRegistrar;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.context.annotation.ConfigurationClassEnhancer.EnhancedConfiguration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.PriorityOrdered;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
@@ -210,7 +208,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Ordered.LOWEST_PRECEDENCE - 1; // within PriorityOrdered, 1 before DeferredRegistryPostProcessor
|
||||
return Ordered.LOWEST_PRECEDENCE; // within PriorityOrdered
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -492,25 +490,6 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
}
|
||||
while (!candidates.isEmpty());
|
||||
|
||||
// Process DeferredBeanRegistrars, if any.
|
||||
List<DeferredBeanRegistrar> deferredBeanRegistrars = new ArrayList<>();
|
||||
for (List<BeanRegistrar> registrars : this.beanRegistrars.values()) {
|
||||
for (BeanRegistrar registrar : registrars) {
|
||||
if (registrar instanceof DeferredBeanRegistrar deferredRegistrar) {
|
||||
deferredBeanRegistrars.add(deferredRegistrar);
|
||||
}
|
||||
}
|
||||
}
|
||||
AnnotationAwareOrderComparator.sort(deferredBeanRegistrars);
|
||||
for (DeferredBeanRegistrar registrar : deferredBeanRegistrars) {
|
||||
if (!(registry instanceof ListableBeanFactory beanFactory)) {
|
||||
throw new IllegalStateException("Cannot support bean registrars since " +
|
||||
registry.getClass().getName() + " does not implement ListableBeanFactory");
|
||||
}
|
||||
registrar.register(new BeanRegistryAdapter(
|
||||
registry, beanFactory, this.environment, registrar.getClass()), this.environment);
|
||||
}
|
||||
|
||||
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
|
||||
if (singletonRegistry != null && !singletonRegistry.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
|
||||
singletonRegistry.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
|
||||
|
||||
@@ -23,7 +23,6 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.beans.factory.BeanRegistrar;
|
||||
import org.springframework.context.DeferredBeanRegistrar;
|
||||
|
||||
/**
|
||||
* Indicates one or more <em>component classes</em> to import — typically
|
||||
@@ -32,9 +31,9 @@ import org.springframework.context.DeferredBeanRegistrar;
|
||||
* <p>Provides functionality equivalent to the {@code <import/>} element in Spring XML.
|
||||
*
|
||||
* <p>Allows for importing {@code @Configuration} classes, {@link ImportSelector},
|
||||
* {@link ImportBeanDefinitionRegistrar}, and {@link BeanRegistrar}/{@link DeferredBeanRegistrar}
|
||||
* implementations, as well as regular component classes
|
||||
* (analogous to {@link AnnotationConfigApplicationContext#register}).
|
||||
* {@link ImportBeanDefinitionRegistrar}, and {@link BeanRegistrar} implementations,
|
||||
* as well as regular component classes (analogous to
|
||||
* {@link AnnotationConfigApplicationContext#register}).
|
||||
*
|
||||
* <p>{@code @Bean} definitions declared in imported {@code @Configuration} classes should be
|
||||
* accessed by using {@link org.springframework.beans.factory.annotation.Autowired @Autowired}
|
||||
@@ -72,8 +71,7 @@ public @interface Import {
|
||||
|
||||
/**
|
||||
* {@link Configuration @Configuration}, {@link ImportSelector},
|
||||
* {@link ImportBeanDefinitionRegistrar},
|
||||
* {@link BeanRegistrar}/{@link DeferredBeanRegistrar},
|
||||
* {@link ImportBeanDefinitionRegistrar}, {@link BeanRegistrar},
|
||||
* or regular component classes to import.
|
||||
*/
|
||||
Class<?>[] value();
|
||||
|
||||
+11
-19
@@ -44,10 +44,8 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.DeferredBeanRegistrar;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.PriorityOrdered;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.io.ProtocolResolver;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
@@ -612,18 +610,13 @@ public class GenericApplicationContext extends AbstractApplicationContext implem
|
||||
*/
|
||||
public void register(BeanRegistrar... registrars) {
|
||||
for (BeanRegistrar registrar : registrars) {
|
||||
if (registrar instanceof DeferredBeanRegistrar deferredRegistrar) {
|
||||
DeferredRegistryPostProcessor pp = (DeferredRegistryPostProcessor)
|
||||
this.beanFactory.getSingleton(DEFERRED_REGISTRY_POST_PROCESSOR_BEAN_NAME);
|
||||
if (pp == null) {
|
||||
pp = new DeferredRegistryPostProcessor();
|
||||
this.beanFactory.registerSingleton(DEFERRED_REGISTRY_POST_PROCESSOR_BEAN_NAME, pp);
|
||||
}
|
||||
pp.addRegistrar(deferredRegistrar);
|
||||
}
|
||||
else {
|
||||
new BeanRegistryAdapter(this.beanFactory, getEnvironment(), registrar.getClass()).register(registrar);
|
||||
DeferredRegistryPostProcessor pp = (DeferredRegistryPostProcessor)
|
||||
this.beanFactory.getSingleton(DEFERRED_REGISTRY_POST_PROCESSOR_BEAN_NAME);
|
||||
if (pp == null) {
|
||||
pp = new DeferredRegistryPostProcessor();
|
||||
this.beanFactory.registerSingleton(DEFERRED_REGISTRY_POST_PROCESSOR_BEAN_NAME, pp);
|
||||
}
|
||||
pp.addRegistrar(registrar);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -671,25 +664,24 @@ public class GenericApplicationContext extends AbstractApplicationContext implem
|
||||
/**
|
||||
* Internal post-processor for invoking DeferredBeanRegistrars at the end
|
||||
* of the BeanDefinitionRegistryPostProcessor PriorityOrdered phase,
|
||||
* right after a potential ConfigurationClassPostProcessor.
|
||||
* right before a potential ConfigurationClassPostProcessor.
|
||||
*/
|
||||
private class DeferredRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
|
||||
|
||||
private final List<DeferredBeanRegistrar> registrars = new ArrayList<>();
|
||||
private final List<BeanRegistrar> registrars = new ArrayList<>();
|
||||
|
||||
public void addRegistrar(DeferredBeanRegistrar registrar) {
|
||||
public void addRegistrar(BeanRegistrar registrar) {
|
||||
this.registrars.add(registrar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Ordered.LOWEST_PRECEDENCE; // within PriorityOrdered, 1 behind ConfigurationClassPostProcessor
|
||||
return Ordered.LOWEST_PRECEDENCE - 1; // within PriorityOrdered, 1 before ConfigurationClassPostProcessor
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
||||
AnnotationAwareOrderComparator.sort(this.registrars);
|
||||
for (DeferredBeanRegistrar registrar : this.registrars) {
|
||||
for (BeanRegistrar registrar : this.registrars) {
|
||||
new BeanRegistryAdapter(beanFactory, getEnvironment(), registrar.getClass()).register(registrar);
|
||||
}
|
||||
}
|
||||
|
||||
+20
-19
@@ -25,6 +25,7 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.testfixture.beans.TestBean;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.testfixture.beans.factory.BarRegistrar;
|
||||
import org.springframework.context.testfixture.beans.factory.ConditionalBeanRegistrar;
|
||||
import org.springframework.context.testfixture.beans.factory.FooRegistrar;
|
||||
import org.springframework.context.testfixture.beans.factory.GenericBeanRegistrar;
|
||||
import org.springframework.context.testfixture.beans.factory.ImportAwareBeanRegistrar;
|
||||
@@ -33,11 +34,10 @@ import org.springframework.context.testfixture.beans.factory.SampleBeanRegistrar
|
||||
import org.springframework.context.testfixture.beans.factory.SampleBeanRegistrar.Foo;
|
||||
import org.springframework.context.testfixture.beans.factory.SampleBeanRegistrar.Init;
|
||||
import org.springframework.context.testfixture.context.annotation.registrar.BeanRegistrarConfiguration;
|
||||
import org.springframework.context.testfixture.context.annotation.registrar.ConditionalBeanRegistrarConfiguration;
|
||||
import org.springframework.context.testfixture.context.annotation.registrar.GenericBeanRegistrarConfiguration;
|
||||
import org.springframework.context.testfixture.context.annotation.registrar.ImportAwareBeanRegistrarConfiguration;
|
||||
import org.springframework.context.testfixture.context.annotation.registrar.MultipleBeanRegistrarsConfiguration;
|
||||
import org.springframework.context.testfixture.context.annotation.registrar.MyDeferredBeanRegistrarConfiguration;
|
||||
import org.springframework.context.testfixture.context.annotation.registrar.MyRegularBeanRegistrarConfiguration;
|
||||
import org.springframework.context.testfixture.context.annotation.registrar.TestBeanConfiguration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -110,40 +110,41 @@ class BeanRegistrarConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void regularBeanRegistrarWithConditionMet() {
|
||||
void programmaticBeanRegistrarWithConditionNotMet() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.register(TestBeanConfiguration.class);
|
||||
context.register(MyRegularBeanRegistrarConfiguration.class);
|
||||
context.refresh();
|
||||
assertThat(context.containsBean("myTestBean")).isTrue();
|
||||
assertThat(context.getBean("myTestBean")).isInstanceOf(TestBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void regularBeanRegistrarWithConditionNotMet() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.register(MyRegularBeanRegistrarConfiguration.class);
|
||||
context.register(new ConditionalBeanRegistrar());
|
||||
context.register(TestBeanConfiguration.class);
|
||||
context.refresh();
|
||||
assertThat(context.containsBean("myTestBean")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void deferredBeanRegistrarWithConditionMet() {
|
||||
void programmaticBeanRegistrarWithConditionMet() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.register(MyDeferredBeanRegistrarConfiguration.class);
|
||||
context.register(TestBeanConfiguration.class);
|
||||
context.register(new ConditionalBeanRegistrar());
|
||||
context.registerBean("testBean", TestBean.class);
|
||||
context.refresh();
|
||||
assertThat(context.containsBean("myTestBean")).isTrue();
|
||||
assertThat(context.getBean("myTestBean")).isInstanceOf(TestBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deferredBeanRegistrarWithConditionNotMet() {
|
||||
void importedBeanRegistrarWithConditionNotMet() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.register(MyDeferredBeanRegistrarConfiguration.class);
|
||||
context.register(ConditionalBeanRegistrarConfiguration.class);
|
||||
context.register(TestBeanConfiguration.class);
|
||||
context.refresh();
|
||||
assertThat(context.containsBean("myTestBean")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void importedBeanRegistrarWithConditionMet() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.register(TestBeanConfiguration.class);
|
||||
context.register(ConditionalBeanRegistrarConfiguration.class);
|
||||
context.refresh();
|
||||
assertThat(context.containsBean("myTestBean")).isTrue();
|
||||
assertThat(context.getBean("myTestBean")).isInstanceOf(TestBean.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-25
@@ -47,9 +47,8 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.testfixture.beans.TestBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.testfixture.beans.factory.ConditionalBeanRegistrar;
|
||||
import org.springframework.context.testfixture.beans.factory.ImportAwareBeanRegistrar;
|
||||
import org.springframework.context.testfixture.beans.factory.MyDeferredBeanRegistrar;
|
||||
import org.springframework.context.testfixture.beans.factory.MyRegularBeanRegistrar;
|
||||
import org.springframework.context.testfixture.beans.factory.SampleBeanRegistrar;
|
||||
import org.springframework.core.DecoratingProxy;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
@@ -649,42 +648,23 @@ class GenericApplicationContextTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void regularBeanRegistrarWithConditionMet() {
|
||||
void beanRegistrarWithConditionNotMet() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.registerBean("testBean", TestBean.class);
|
||||
context.register(new MyRegularBeanRegistrar());
|
||||
context.refresh();
|
||||
assertThat(context.containsBean("myTestBean")).isTrue();
|
||||
assertThat(context.getBean("myTestBean")).isInstanceOf(TestBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void regularBeanRegistrarWithConditionNotMet() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.register(new MyRegularBeanRegistrar());
|
||||
context.registerBean("testBean", TestBean.class);
|
||||
context.register(new ConditionalBeanRegistrar());
|
||||
context.refresh();
|
||||
assertThat(context.containsBean("myTestBean")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void deferredBeanRegistrarWithConditionMet() {
|
||||
void beanRegistrarWithConditionMet() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.register(new MyDeferredBeanRegistrar());
|
||||
context.register(new ConditionalBeanRegistrar());
|
||||
context.registerBean("testBean", TestBean.class);
|
||||
context.refresh();
|
||||
assertThat(context.containsBean("myTestBean")).isTrue();
|
||||
assertThat(context.getBean("myTestBean")).isInstanceOf(TestBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deferredBeanRegistrarWithConditionNotMet() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.register(new MyDeferredBeanRegistrar());
|
||||
context.refresh();
|
||||
assertThat(context.containsBean("myTestBean")).isFalse();
|
||||
}
|
||||
|
||||
|
||||
private MergedBeanDefinitionPostProcessor registerMockMergedBeanDefinitionPostProcessor(GenericApplicationContext context) {
|
||||
MergedBeanDefinitionPostProcessor bpp = mock();
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ import org.springframework.beans.testfixture.beans.TestBean;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
public class MyRegularBeanRegistrar implements BeanRegistrar {
|
||||
public class ConditionalBeanRegistrar implements BeanRegistrar {
|
||||
|
||||
@Override
|
||||
public void register(BeanRegistry registry, Environment env) {
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.context.testfixture.beans.factory;
|
||||
|
||||
import org.springframework.beans.factory.BeanRegistry;
|
||||
import org.springframework.beans.testfixture.beans.TestBean;
|
||||
import org.springframework.context.DeferredBeanRegistrar;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
public class MyDeferredBeanRegistrar implements DeferredBeanRegistrar {
|
||||
|
||||
@Override
|
||||
public void register(BeanRegistry registry, Environment env) {
|
||||
if (registry.containsBean("testBean") &&
|
||||
registry.containsBean(TestBean.class) &&
|
||||
registry.containsBean(new ParameterizedTypeReference<Comparable<Object>>() {
|
||||
})) {
|
||||
registry.registerBean("myTestBean", TestBean.class);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+3
-3
@@ -18,9 +18,9 @@ package org.springframework.context.testfixture.context.annotation.registrar;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.testfixture.beans.factory.MyDeferredBeanRegistrar;
|
||||
import org.springframework.context.testfixture.beans.factory.ConditionalBeanRegistrar;
|
||||
|
||||
@Configuration
|
||||
@Import(MyDeferredBeanRegistrar.class)
|
||||
public class MyDeferredBeanRegistrarConfiguration {
|
||||
@Import(ConditionalBeanRegistrar.class)
|
||||
public class ConditionalBeanRegistrarConfiguration {
|
||||
}
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.context.testfixture.context.annotation.registrar;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.testfixture.beans.factory.MyRegularBeanRegistrar;
|
||||
|
||||
@Configuration
|
||||
@Import(MyRegularBeanRegistrar.class)
|
||||
public class MyRegularBeanRegistrarConfiguration {
|
||||
}
|
||||
Reference in New Issue
Block a user