From bd8855448555c075bdd3e41fcee316787d7d3007 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Sat, 8 Mar 2025 16:42:58 -0800 Subject: [PATCH] Allow chained BeanRegistry registration Add a `register(BeanRegistry registry)` method to `BeanRegistry` to allow registration chaining. --- .../beans/factory/BeanRegistry.java | 7 +++ .../factory/support/BeanRegistryAdapter.java | 19 ++++++-- .../support/BeanRegistryAdapterTests.java | 48 +++++++++++-------- ...onfigurationClassBeanDefinitionReader.java | 2 +- .../ConfigurationClassPostProcessor.java | 6 +-- 5 files changed, 55 insertions(+), 27 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/BeanRegistry.java b/spring-beans/src/main/java/org/springframework/beans/factory/BeanRegistry.java index 26cbc577acd1..87547aa4a867 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/BeanRegistry.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/BeanRegistry.java @@ -77,6 +77,13 @@ public interface BeanRegistry { */ void registerBean(String name, Class beanClass, Consumer> customizer); + /** + * Register beans using given {@link BeanRegistrar}. + * @param registrar the bean registrar that will be called to register + * additional beans + */ + void register(BeanRegistrar registrar); + /** * Specification for customizing a bean. * @param the bean type diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanRegistryAdapter.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanRegistryAdapter.java index dfc0c0aac98f..d2a1e9388fde 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanRegistryAdapter.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanRegistryAdapter.java @@ -31,6 +31,8 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionCustomizer; import org.springframework.core.ResolvableType; +import org.springframework.core.env.Environment; +import org.springframework.util.Assert; import org.springframework.util.MultiValueMap; /** @@ -46,21 +48,26 @@ public class BeanRegistryAdapter implements BeanRegistry { private final ListableBeanFactory beanFactory; + private final Environment environment; + private final Class beanRegistrarClass; private final @Nullable MultiValueMap customizers; public BeanRegistryAdapter(BeanDefinitionRegistry beanRegistry, ListableBeanFactory beanFactory, - Class beanRegistrarClass) { - this(beanRegistry, beanFactory, beanRegistrarClass, null); + Environment environment, Class beanRegistrarClass) { + + this(beanRegistry, beanFactory, environment, beanRegistrarClass, null); } public BeanRegistryAdapter(BeanDefinitionRegistry beanRegistry, ListableBeanFactory beanFactory, - Class beanRegistrarClass, @Nullable MultiValueMap customizers) { + Environment environment, Class beanRegistrarClass, + @Nullable MultiValueMap customizers) { this.beanRegistry = beanRegistry; this.beanFactory = beanFactory; + this.environment = environment; this.beanRegistrarClass = beanRegistrarClass; this.customizers = customizers; } @@ -102,6 +109,12 @@ public void registerBean(String name, Class beanClass, Consumer> this.beanRegistry.registerBeanDefinition(name, beanDefinition); } + @Override + public void register(BeanRegistrar registrar) { + Assert.notNull(registrar, "'registrar' must not be null"); + registrar.register(this, this.environment); + } + /** * {@link RootBeanDefinition} subclass for {@code #registerBean} based diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanRegistryAdapterTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanRegistryAdapterTests.java index 81e0c3840e98..7c174a38ee75 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanRegistryAdapterTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanRegistryAdapterTests.java @@ -41,7 +41,7 @@ public class BeanRegistryAdapterTests { @Test void defaultBackgroundInit() { - BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, DefaultBeanRegistrar.class); + BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, this.env, DefaultBeanRegistrar.class); new DefaultBeanRegistrar().register(adapter, env); AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) this.beanFactory.getBeanDefinition("foo"); assertThat(beanDefinition.isBackgroundInit()).isFalse(); @@ -49,7 +49,7 @@ void defaultBackgroundInit() { @Test void enableBackgroundInit() { - BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, BackgroundInitBeanRegistrar.class); + BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, this.env, BackgroundInitBeanRegistrar.class); new BackgroundInitBeanRegistrar().register(adapter, env); AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) this.beanFactory.getBeanDefinition("foo"); assertThat(beanDefinition.isBackgroundInit()).isTrue(); @@ -57,7 +57,7 @@ void enableBackgroundInit() { @Test void defaultDescription() { - BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, DefaultBeanRegistrar.class); + BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, this.env, DefaultBeanRegistrar.class); new DefaultBeanRegistrar().register(adapter, env); BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("foo"); assertThat(beanDefinition.getDescription()).isNull(); @@ -65,7 +65,7 @@ void defaultDescription() { @Test void customDescription() { - BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, CustomDescriptionBeanRegistrar.class); + BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, this.env, CustomDescriptionBeanRegistrar.class); new CustomDescriptionBeanRegistrar().register(adapter, env); BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("foo"); assertThat(beanDefinition.getDescription()).isEqualTo("custom"); @@ -73,7 +73,7 @@ void customDescription() { @Test void defaultFallback() { - BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, DefaultBeanRegistrar.class); + BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, this.env, DefaultBeanRegistrar.class); new DefaultBeanRegistrar().register(adapter, env); BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("foo"); assertThat(beanDefinition.isFallback()).isFalse(); @@ -81,7 +81,7 @@ void defaultFallback() { @Test void enableFallback() { - BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, FallbackBeanRegistrar.class); + BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, this.env, FallbackBeanRegistrar.class); new FallbackBeanRegistrar().register(adapter, env); BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("foo"); assertThat(beanDefinition.isFallback()).isTrue(); @@ -89,7 +89,7 @@ void enableFallback() { @Test void defaultRole() { - BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, DefaultBeanRegistrar.class); + BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, this.env, DefaultBeanRegistrar.class); new DefaultBeanRegistrar().register(adapter, env); BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("foo"); assertThat(beanDefinition.getRole()).isEqualTo(AbstractBeanDefinition.ROLE_APPLICATION); @@ -97,7 +97,7 @@ void defaultRole() { @Test void infrastructureRole() { - BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, InfrastructureBeanRegistrar.class); + BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, this.env, InfrastructureBeanRegistrar.class); new InfrastructureBeanRegistrar().register(adapter, env); BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("foo"); assertThat(beanDefinition.getRole()).isEqualTo(AbstractBeanDefinition.ROLE_INFRASTRUCTURE); @@ -105,7 +105,7 @@ void infrastructureRole() { @Test void defaultLazyInit() { - BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, DefaultBeanRegistrar.class); + BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, this.env, DefaultBeanRegistrar.class); new DefaultBeanRegistrar().register(adapter, env); AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) this.beanFactory.getBeanDefinition("foo"); assertThat(beanDefinition.isLazyInit()).isFalse(); @@ -113,7 +113,7 @@ void defaultLazyInit() { @Test void enableLazyInit() { - BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, LazyInitBeanRegistrar.class); + BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, this.env, LazyInitBeanRegistrar.class); new LazyInitBeanRegistrar().register(adapter, env); AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) this.beanFactory.getBeanDefinition("foo"); assertThat(beanDefinition.isLazyInit()).isTrue(); @@ -121,7 +121,7 @@ void enableLazyInit() { @Test void defaultAutowirable() { - BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, DefaultBeanRegistrar.class); + BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, this.env, DefaultBeanRegistrar.class); new DefaultBeanRegistrar().register(adapter, env); AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) this.beanFactory.getBeanDefinition("foo"); assertThat(beanDefinition.isAutowireCandidate()).isTrue(); @@ -129,7 +129,7 @@ void defaultAutowirable() { @Test void notAutowirable() { - BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, NotAutowirableBeanRegistrar.class); + BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, this.env, NotAutowirableBeanRegistrar.class); new NotAutowirableBeanRegistrar().register(adapter, env); AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) this.beanFactory.getBeanDefinition("foo"); assertThat(beanDefinition.isAutowireCandidate()).isFalse(); @@ -137,7 +137,7 @@ void notAutowirable() { @Test void defaultOrder() { - BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, DefaultBeanRegistrar.class); + BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, this.env, DefaultBeanRegistrar.class); new DefaultBeanRegistrar().register(adapter, env); AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) this.beanFactory.getBeanDefinition("foo"); Integer order = (Integer)beanDefinition.getAttribute(AbstractBeanDefinition.ORDER_ATTRIBUTE); @@ -146,7 +146,7 @@ void defaultOrder() { @Test void customOrder() { - BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, CustomOrderBeanRegistrar.class); + BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, this.env, CustomOrderBeanRegistrar.class); new CustomOrderBeanRegistrar().register(adapter, env); AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) this.beanFactory.getBeanDefinition("foo"); Integer order = (Integer)beanDefinition.getAttribute(AbstractBeanDefinition.ORDER_ATTRIBUTE); @@ -155,7 +155,7 @@ void customOrder() { @Test void defaultPrimary() { - BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, DefaultBeanRegistrar.class); + BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, this.env, DefaultBeanRegistrar.class); new DefaultBeanRegistrar().register(adapter, env); BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("foo"); assertThat(beanDefinition.isPrimary()).isFalse(); @@ -163,7 +163,7 @@ void defaultPrimary() { @Test void enablePrimary() { - BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, PrimaryBeanRegistrar.class); + BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, this.env, PrimaryBeanRegistrar.class); new PrimaryBeanRegistrar().register(adapter, env); BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("foo"); assertThat(beanDefinition.isPrimary()).isTrue(); @@ -171,7 +171,7 @@ void enablePrimary() { @Test void defaultScope() { - BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, DefaultBeanRegistrar.class); + BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, this.env, DefaultBeanRegistrar.class); new DefaultBeanRegistrar().register(adapter, env); BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("foo"); assertThat(beanDefinition.getScope()).isEqualTo(AbstractBeanDefinition.SCOPE_DEFAULT); @@ -179,7 +179,7 @@ void defaultScope() { @Test void prototypeScope() { - BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, PrototypeBeanRegistrar.class); + BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, this.env, PrototypeBeanRegistrar.class); new PrototypeBeanRegistrar().register(adapter, env); BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("foo"); assertThat(beanDefinition.getScope()).isEqualTo(AbstractBeanDefinition.SCOPE_PROTOTYPE); @@ -187,7 +187,7 @@ void prototypeScope() { @Test void defaultSupplier() { - BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, DefaultBeanRegistrar.class); + BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, this.env, DefaultBeanRegistrar.class); new DefaultBeanRegistrar().register(adapter, env); AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition)this.beanFactory.getBeanDefinition("foo"); assertThat(beanDefinition.getInstanceSupplier()).isNull(); @@ -195,7 +195,7 @@ void defaultSupplier() { @Test void customSupplier() { - BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, SupplierBeanRegistrar.class); + BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, this.env, SupplierBeanRegistrar.class); new SupplierBeanRegistrar().register(adapter, env); AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition)this.beanFactory.getBeanDefinition("foo"); Supplier supplier = beanDefinition.getInstanceSupplier(); @@ -203,6 +203,14 @@ void customSupplier() { assertThat(supplier.get()).isNotNull().isInstanceOf(Foo.class); } + @Test + void registerViaAnotherRegistrar() { + BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, this.env, DefaultBeanRegistrar.class); + BeanRegistrar registrar = (registry, env) -> registry.register(new DefaultBeanRegistrar()); + registrar.register(adapter, env); + assertThat(this.beanFactory.getBeanDefinition("foo")).isNotNull(); + } + private static class DefaultBeanRegistrar implements BeanRegistrar { diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java index 1688542e13f4..de14187568cd 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java @@ -409,7 +409,7 @@ private void loadBeanDefinitionsFromBeanRegistrars(Set registrars "Cannot support bean registrars since " + this.registry.getClass().getName() + " does not implement BeanDefinitionRegistry"); registrars.forEach(registrar -> registrar.register(new BeanRegistryAdapter(this.registry, - (ListableBeanFactory) this.registry, registrar.getClass()), this.environment)); + (ListableBeanFactory) this.registry, this.environment, registrar.getClass()), this.environment)); } diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java index 57f6ee7d6aef..5596c1d166d3 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java @@ -936,10 +936,10 @@ private CodeBlock generateCustomizerMap() { private CodeBlock generateRegisterCode() { Builder code = CodeBlock.builder(); for (BeanRegistrar beanRegistrar : this.beanRegistrars) { - code.addStatement("new $T().register(new $T(($T)$L, $L, $T.class, $L), $L)", beanRegistrar.getClass(), + code.addStatement("new $T().register(new $T(($T)$L, $L, $L, $T.class, $L), $L)", beanRegistrar.getClass(), BeanRegistryAdapter.class, BeanDefinitionRegistry.class, BeanFactoryInitializationCode.BEAN_FACTORY_VARIABLE, - BeanFactoryInitializationCode.BEAN_FACTORY_VARIABLE, beanRegistrar.getClass(), CUSTOMIZER_MAP_VARIABLE, - ENVIRONMENT_VARIABLE); + BeanFactoryInitializationCode.BEAN_FACTORY_VARIABLE, ENVIRONMENT_VARIABLE, beanRegistrar.getClass(), + CUSTOMIZER_MAP_VARIABLE, ENVIRONMENT_VARIABLE); } return code.build(); }