Introduce first-class support for programmatic bean registration
This commit introduces a new BeanRegistrar interface that can be implemented to register beans programmatically in a concise and flexible way. Those bean registrar implementations are typically imported with an `@Import` annotation on `@Configuration` classes. See BeanRegistrarConfigurationTests for a concrete example. See gh-18353
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2002-2025 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.beans.factory;
|
||||
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
/**
|
||||
* Contract for registering beans programmatically.
|
||||
*
|
||||
* <p>Typically imported with an {@link org.springframework.context.annotation.Import @Import}
|
||||
* annotation on {@link org.springframework.context.annotation.Configuration @Configuration}
|
||||
* classes.
|
||||
* <pre class="code">
|
||||
* @Configuration
|
||||
* @Import(MyBeanRegistrar.class)
|
||||
* class MyConfiguration {
|
||||
* }</pre>
|
||||
*
|
||||
* <p>The bean registrar implementation uses {@link BeanRegistry} and {@link Environment}
|
||||
* APIs to register beans programmatically in a concise and flexible way.
|
||||
* <pre class="code">
|
||||
* class MyBeanRegistrar implements BeanRegistrar {
|
||||
*
|
||||
* @Override
|
||||
* public void register(BeanRegistry registry, Environment env) {
|
||||
* registry.registerBean("foo", Foo.class);
|
||||
* registry.registerBean("bar", Bar.class, spec -> spec
|
||||
* .prototype()
|
||||
* .lazyInit()
|
||||
* .description("Custom description")
|
||||
* .supplier(context -> new Bar(context.bean(Foo.class))));
|
||||
* if (env.matchesProfiles("baz")) {
|
||||
* registry.registerBean(Baz.class, spec -> spec
|
||||
* .supplier(context -> new Baz("Hello World!")));
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p>In Kotlin, it is recommended to use {@code BeanRegistrarDsl} instead of
|
||||
* implementing {@code BeanRegistrar}.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 7.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface BeanRegistrar {
|
||||
|
||||
/**
|
||||
* Register beans in a programmatic way.
|
||||
* @param registry the bean registry
|
||||
* @param env the environment that can be used to get the active profile or some properties
|
||||
*/
|
||||
void register(BeanRegistry registry, Environment env);
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright 2002-2025 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.beans.factory;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
/**
|
||||
* Used in {@link BeanRegistrar#register(BeanRegistry, Environment)} to expose
|
||||
* programmatic bean registration capabilities.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 7.0
|
||||
*/
|
||||
public interface BeanRegistry {
|
||||
|
||||
/**
|
||||
* Register a bean from the given bean class, which will be instantiated
|
||||
* using the related {@link BeanUtils#getResolvableConstructor resolvable constructor}
|
||||
* if any.
|
||||
* @param beanClass the class of the bean
|
||||
* @return the generated bean name
|
||||
*/
|
||||
<T> String registerBean(Class<T> beanClass);
|
||||
|
||||
/**
|
||||
* Register a bean from the given bean class, customizing it with the customizer
|
||||
* callback. The bean will be instantiated using the supplier that can be
|
||||
* configured in the customizer callback, or will be tentatively instantiated
|
||||
* with its {@link BeanUtils#getResolvableConstructor resolvable constructor}
|
||||
* otherwise.
|
||||
* @param beanClass the class of the bean
|
||||
* @param customizer callback to customize other bean properties than the name
|
||||
* @return the generated bean name
|
||||
*/
|
||||
<T> String registerBean(Class<T> beanClass, Consumer<Spec<T>> customizer);
|
||||
|
||||
/**
|
||||
* Register a bean from the given bean class, which will be instantiated
|
||||
* using the related {@link BeanUtils#getResolvableConstructor resolvable constructor}
|
||||
* if any.
|
||||
* @param name the name of the bean
|
||||
* @param beanClass the class of the bean
|
||||
*/
|
||||
<T> void registerBean(String name, Class<T> beanClass);
|
||||
|
||||
/**
|
||||
* Register a bean from the given bean class, customizing it with the customizer
|
||||
* callback. The bean will be instantiated using the supplier that can be
|
||||
* configured in the customizer callback, or will be tentatively instantiated with its
|
||||
* {@link BeanUtils#getResolvableConstructor resolvable constructor} otherwise.
|
||||
* @param name the name of the bean
|
||||
* @param beanClass the class of the bean
|
||||
* @param customizer callback to customize other bean properties than the name
|
||||
*/
|
||||
<T> void registerBean(String name, Class<T> beanClass, Consumer<Spec<T>> customizer);
|
||||
|
||||
/**
|
||||
* Specification for customizing a bean.
|
||||
* @param <T> the bean type
|
||||
*/
|
||||
interface Spec<T> {
|
||||
|
||||
/**
|
||||
* Allow for instantiating this bean on a background thread.
|
||||
* @see AbstractBeanDefinition#setBackgroundInit(boolean)
|
||||
*/
|
||||
Spec<T> backgroundInit();
|
||||
|
||||
/**
|
||||
* Set a human-readable description of this bean.
|
||||
* @see BeanDefinition#setDescription(String)
|
||||
*/
|
||||
Spec<T> description(String description);
|
||||
|
||||
/**
|
||||
* Configure this bean as a fallback autowire candidate.
|
||||
* @see BeanDefinition#setFallback(boolean)
|
||||
* @see #primary
|
||||
*/
|
||||
Spec<T> fallback();
|
||||
|
||||
/**
|
||||
* Hint that this bean has an infrastructure role, meaning it has no
|
||||
* relevance to the end-user.
|
||||
* @see BeanDefinition#setRole(int)
|
||||
* @see BeanDefinition#ROLE_INFRASTRUCTURE
|
||||
*/
|
||||
Spec<T> infrastructure();
|
||||
|
||||
/**
|
||||
* Configure this bean as lazily initialized.
|
||||
* @see BeanDefinition#setLazyInit(boolean)
|
||||
*/
|
||||
Spec<T> lazyInit();
|
||||
|
||||
/**
|
||||
* Configure this bean as not a candidate for getting autowired into some
|
||||
* other bean.
|
||||
* @see BeanDefinition#setAutowireCandidate(boolean)
|
||||
*/
|
||||
Spec<T> notAutowirable();
|
||||
|
||||
/**
|
||||
* The sort order of this bean. This is analogous to the
|
||||
* {@code @Order} annotation.
|
||||
* @see AbstractBeanDefinition#ORDER_ATTRIBUTE
|
||||
*/
|
||||
Spec<T> order(int order);
|
||||
|
||||
/**
|
||||
* Configure this bean as a primary autowire candidate.
|
||||
* @see BeanDefinition#setPrimary(boolean)
|
||||
* @see #fallback
|
||||
*/
|
||||
Spec<T> primary();
|
||||
|
||||
/**
|
||||
* Configure this bean with a prototype scope.
|
||||
* @see BeanDefinition#setScope(String)
|
||||
* @see BeanDefinition#SCOPE_PROTOTYPE
|
||||
*/
|
||||
Spec<T> prototype();
|
||||
|
||||
/**
|
||||
* Set the supplier to construct a bean instance.
|
||||
* @see AbstractBeanDefinition#setInstanceSupplier(Supplier)
|
||||
*/
|
||||
Spec<T> supplier(Function<SupplierContext, T> supplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Context available from the bean instance supplier designed to give access
|
||||
* to bean dependencies.
|
||||
*/
|
||||
interface SupplierContext {
|
||||
|
||||
/**
|
||||
* Return the bean instance that uniquely matches the given object type,
|
||||
* if any.
|
||||
* @param requiredType type the bean must match; can be an interface or
|
||||
* superclass
|
||||
* @return an instance of the single bean matching the required type
|
||||
* @see BeanFactory#getBean(String)
|
||||
*/
|
||||
<T> T bean(Class<T> requiredType) throws BeansException;
|
||||
|
||||
/**
|
||||
* Return an instance, which may be shared or independent, of the
|
||||
* specified bean.
|
||||
* @param name the name of the bean to retrieve
|
||||
* @param requiredType type the bean must match; can be an interface or superclass
|
||||
* @return an instance of the bean.
|
||||
* @see BeanFactory#getBean(String, Class)
|
||||
*/
|
||||
<T> T bean(String name, Class<T> requiredType) throws BeansException;
|
||||
|
||||
/**
|
||||
* Return a provider for the specified bean, allowing for lazy on-demand retrieval
|
||||
* of instances, including availability and uniqueness options.
|
||||
* <p>For matching a generic type, consider {@link #beanProvider(ResolvableType)}.
|
||||
* @param requiredType type the bean must match; can be an interface or superclass
|
||||
* @return a corresponding provider handle
|
||||
* @see BeanFactory#getBeanProvider(Class)
|
||||
*/
|
||||
<T> ObjectProvider<T> beanProvider(Class<T> requiredType);
|
||||
|
||||
/**
|
||||
* Return a provider for the specified bean, allowing for lazy on-demand retrieval
|
||||
* of instances, including availability and uniqueness options. This variant allows
|
||||
* for specifying a generic type to match, similar to reflective injection points
|
||||
* with generic type declarations in method/constructor parameters.
|
||||
* <p>Note that collections of beans are not supported here, in contrast to reflective
|
||||
* injection points. For programmatically retrieving a list of beans matching a
|
||||
* specific type, specify the actual bean type as an argument here and subsequently
|
||||
* use {@link ObjectProvider#orderedStream()} or its lazy streaming/iteration options.
|
||||
* <p>Also, generics matching is strict here, as per the Java assignment rules.
|
||||
* For lenient fallback matching with unchecked semantics (similar to the 'unchecked'
|
||||
* Java compiler warning), consider calling {@link #beanProvider(Class)} with the
|
||||
* raw type as a second step if no full generic match is
|
||||
* {@link ObjectProvider#getIfAvailable() available} with this variant.
|
||||
* @param requiredType type the bean must match; can be a generic type declaration
|
||||
* @return a corresponding provider handle
|
||||
* @see BeanFactory#getBeanProvider(ResolvableType)
|
||||
*/
|
||||
<T> ObjectProvider<T> beanProvider(ResolvableType requiredType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright 2002-2025 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.beans.factory.support;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanRegistrar;
|
||||
import org.springframework.beans.factory.BeanRegistry;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionCustomizer;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* {@link BeanRegistry} implementation that delegates to
|
||||
* {@link BeanDefinitionRegistry} and {@link ListableBeanFactory}.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 7.0
|
||||
*/
|
||||
public class BeanRegistryAdapter implements BeanRegistry {
|
||||
|
||||
private final BeanDefinitionRegistry beanRegistry;
|
||||
|
||||
private final ListableBeanFactory beanFactory;
|
||||
|
||||
private final Class<? extends BeanRegistrar> beanRegistrarClass;
|
||||
|
||||
private final @Nullable MultiValueMap<String, BeanDefinitionCustomizer> customizers;
|
||||
|
||||
|
||||
public BeanRegistryAdapter(BeanDefinitionRegistry beanRegistry, ListableBeanFactory beanFactory,
|
||||
Class<? extends BeanRegistrar> beanRegistrarClass) {
|
||||
this(beanRegistry, beanFactory, beanRegistrarClass, null);
|
||||
}
|
||||
|
||||
public BeanRegistryAdapter(BeanDefinitionRegistry beanRegistry, ListableBeanFactory beanFactory,
|
||||
Class<? extends BeanRegistrar> beanRegistrarClass, @Nullable MultiValueMap<String, BeanDefinitionCustomizer> customizers) {
|
||||
|
||||
this.beanRegistry = beanRegistry;
|
||||
this.beanFactory = beanFactory;
|
||||
this.beanRegistrarClass = beanRegistrarClass;
|
||||
this.customizers = customizers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> String registerBean(Class<T> beanClass) {
|
||||
String beanName = BeanDefinitionReaderUtils.uniqueBeanName(beanClass.getName(), this.beanRegistry);
|
||||
registerBean(beanName, beanClass);
|
||||
return beanName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> String registerBean(Class<T> beanClass, Consumer<Spec<T>> customizer) {
|
||||
String beanName = BeanDefinitionReaderUtils.uniqueBeanName(beanClass.getName(), this.beanRegistry);
|
||||
registerBean(beanName, beanClass, customizer);
|
||||
return beanName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void registerBean(String name, Class<T> beanClass) {
|
||||
BeanRegistrarBeanDefinition beanDefinition = new BeanRegistrarBeanDefinition(beanClass, this.beanRegistrarClass);
|
||||
if (this.customizers != null && this.customizers.containsKey(name)) {
|
||||
for (BeanDefinitionCustomizer customizer : this.customizers.get(name)) {
|
||||
customizer.customize(beanDefinition);
|
||||
}
|
||||
}
|
||||
this.beanRegistry.registerBeanDefinition(name, beanDefinition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void registerBean(String name, Class<T> beanClass, Consumer<Spec<T>> spec) {
|
||||
BeanRegistrarBeanDefinition beanDefinition = new BeanRegistrarBeanDefinition(beanClass, this.beanRegistrarClass);
|
||||
spec.accept(new BeanSpecAdapter<>(beanDefinition, this.beanFactory));
|
||||
if (this.customizers != null && this.customizers.containsKey(name)) {
|
||||
for (BeanDefinitionCustomizer customizer : this.customizers.get(name)) {
|
||||
customizer.customize(beanDefinition);
|
||||
}
|
||||
}
|
||||
this.beanRegistry.registerBeanDefinition(name, beanDefinition);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link RootBeanDefinition} subclass for {@code #registerBean} based
|
||||
* registrations with constructors resolution match{@link BeanUtils#getResolvableConstructor}
|
||||
* behavior. It also sets the bean registrar class as the source.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
private static class BeanRegistrarBeanDefinition extends RootBeanDefinition {
|
||||
|
||||
public BeanRegistrarBeanDefinition(Class<?> beanClass, Class<? extends BeanRegistrar> beanRegistrarClass) {
|
||||
super(beanClass);
|
||||
this.setSource(beanRegistrarClass);
|
||||
this.setAttribute("aotProcessingIgnoreRegistration", true);
|
||||
}
|
||||
|
||||
public BeanRegistrarBeanDefinition(BeanRegistrarBeanDefinition original) {
|
||||
super(original);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Constructor<?> @Nullable [] getPreferredConstructors() {
|
||||
if (this.getInstanceSupplier() != null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new Constructor<?>[] { BeanUtils.getResolvableConstructor(getBeanClass()) };
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RootBeanDefinition cloneBeanDefinition() {
|
||||
return new BeanRegistrarBeanDefinition(this);
|
||||
}
|
||||
}
|
||||
|
||||
static class BeanSpecAdapter<T> implements Spec<T> {
|
||||
|
||||
private final RootBeanDefinition beanDefinition;
|
||||
|
||||
private final ListableBeanFactory beanFactory;
|
||||
|
||||
public BeanSpecAdapter(RootBeanDefinition beanDefinition, ListableBeanFactory beanFactory) {
|
||||
this.beanDefinition = beanDefinition;
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spec<T> backgroundInit() {
|
||||
this.beanDefinition.setBackgroundInit(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spec<T> fallback() {
|
||||
this.beanDefinition.setFallback(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spec<T> primary() {
|
||||
this.beanDefinition.setPrimary(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spec<T> description(String description) {
|
||||
this.beanDefinition.setDescription(description);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spec<T> infrastructure() {
|
||||
this.beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spec<T> lazyInit() {
|
||||
this.beanDefinition.setLazyInit(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spec<T> notAutowirable() {
|
||||
this.beanDefinition.setAutowireCandidate(false);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spec<T> order(int order) {
|
||||
this.beanDefinition.setAttribute(AbstractBeanDefinition.ORDER_ATTRIBUTE, order);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spec<T> prototype() {
|
||||
this.beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spec<T> supplier(Function<SupplierContext, T> supplier) {
|
||||
this.beanDefinition.setInstanceSupplier(() ->
|
||||
supplier.apply(new SupplierContextAdapter(this.beanFactory)));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
static class SupplierContextAdapter implements SupplierContext {
|
||||
|
||||
private final ListableBeanFactory beanFactory;
|
||||
|
||||
public SupplierContextAdapter(ListableBeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T bean(Class<T> requiredType) throws BeansException {
|
||||
return this.beanFactory.getBean(requiredType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T bean(String name, Class<T> requiredType) throws BeansException {
|
||||
return this.beanFactory.getBean(name, requiredType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ObjectProvider<T> beanProvider(Class<T> requiredType) {
|
||||
return this.beanFactory.getBeanProvider(requiredType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ObjectProvider<T> beanProvider(ResolvableType requiredType) {
|
||||
return this.beanFactory.getBeanProvider(requiredType);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Copyright 2002-2025 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.beans.factory.support;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanRegistrar;
|
||||
import org.springframework.beans.factory.BeanRegistry;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link BeanRegistryAdapter}.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
public class BeanRegistryAdapterTests {
|
||||
|
||||
private final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
|
||||
private final Environment env = new StandardEnvironment();
|
||||
|
||||
@Test
|
||||
void defaultBackgroundInit() {
|
||||
BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, DefaultBeanRegistrar.class);
|
||||
new DefaultBeanRegistrar().register(adapter, env);
|
||||
AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) this.beanFactory.getBeanDefinition("foo");
|
||||
assertThat(beanDefinition.isBackgroundInit()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void enableBackgroundInit() {
|
||||
BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, BackgroundInitBeanRegistrar.class);
|
||||
new BackgroundInitBeanRegistrar().register(adapter, env);
|
||||
AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) this.beanFactory.getBeanDefinition("foo");
|
||||
assertThat(beanDefinition.isBackgroundInit()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultDescription() {
|
||||
BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, DefaultBeanRegistrar.class);
|
||||
new DefaultBeanRegistrar().register(adapter, env);
|
||||
BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("foo");
|
||||
assertThat(beanDefinition.getDescription()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void customDescription() {
|
||||
BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, CustomDescriptionBeanRegistrar.class);
|
||||
new CustomDescriptionBeanRegistrar().register(adapter, env);
|
||||
BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("foo");
|
||||
assertThat(beanDefinition.getDescription()).isEqualTo("custom");
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultFallback() {
|
||||
BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, DefaultBeanRegistrar.class);
|
||||
new DefaultBeanRegistrar().register(adapter, env);
|
||||
BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("foo");
|
||||
assertThat(beanDefinition.isFallback()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void enableFallback() {
|
||||
BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, FallbackBeanRegistrar.class);
|
||||
new FallbackBeanRegistrar().register(adapter, env);
|
||||
BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("foo");
|
||||
assertThat(beanDefinition.isFallback()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultRole() {
|
||||
BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, DefaultBeanRegistrar.class);
|
||||
new DefaultBeanRegistrar().register(adapter, env);
|
||||
BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("foo");
|
||||
assertThat(beanDefinition.getRole()).isEqualTo(AbstractBeanDefinition.ROLE_APPLICATION);
|
||||
}
|
||||
|
||||
@Test
|
||||
void infrastructureRole() {
|
||||
BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, InfrastructureBeanRegistrar.class);
|
||||
new InfrastructureBeanRegistrar().register(adapter, env);
|
||||
BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("foo");
|
||||
assertThat(beanDefinition.getRole()).isEqualTo(AbstractBeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultLazyInit() {
|
||||
BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, DefaultBeanRegistrar.class);
|
||||
new DefaultBeanRegistrar().register(adapter, env);
|
||||
AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) this.beanFactory.getBeanDefinition("foo");
|
||||
assertThat(beanDefinition.isLazyInit()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void enableLazyInit() {
|
||||
BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, LazyInitBeanRegistrar.class);
|
||||
new LazyInitBeanRegistrar().register(adapter, env);
|
||||
AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) this.beanFactory.getBeanDefinition("foo");
|
||||
assertThat(beanDefinition.isLazyInit()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultAutowirable() {
|
||||
BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, DefaultBeanRegistrar.class);
|
||||
new DefaultBeanRegistrar().register(adapter, env);
|
||||
AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) this.beanFactory.getBeanDefinition("foo");
|
||||
assertThat(beanDefinition.isAutowireCandidate()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void notAutowirable() {
|
||||
BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, NotAutowirableBeanRegistrar.class);
|
||||
new NotAutowirableBeanRegistrar().register(adapter, env);
|
||||
AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) this.beanFactory.getBeanDefinition("foo");
|
||||
assertThat(beanDefinition.isAutowireCandidate()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultOrder() {
|
||||
BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, DefaultBeanRegistrar.class);
|
||||
new DefaultBeanRegistrar().register(adapter, env);
|
||||
AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) this.beanFactory.getBeanDefinition("foo");
|
||||
Integer order = (Integer)beanDefinition.getAttribute(AbstractBeanDefinition.ORDER_ATTRIBUTE);
|
||||
assertThat(order).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void customOrder() {
|
||||
BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, CustomOrderBeanRegistrar.class);
|
||||
new CustomOrderBeanRegistrar().register(adapter, env);
|
||||
AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) this.beanFactory.getBeanDefinition("foo");
|
||||
Integer order = (Integer)beanDefinition.getAttribute(AbstractBeanDefinition.ORDER_ATTRIBUTE);
|
||||
assertThat(order).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultPrimary() {
|
||||
BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, DefaultBeanRegistrar.class);
|
||||
new DefaultBeanRegistrar().register(adapter, env);
|
||||
BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("foo");
|
||||
assertThat(beanDefinition.isPrimary()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void enablePrimary() {
|
||||
BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, PrimaryBeanRegistrar.class);
|
||||
new PrimaryBeanRegistrar().register(adapter, env);
|
||||
BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("foo");
|
||||
assertThat(beanDefinition.isPrimary()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultScope() {
|
||||
BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, DefaultBeanRegistrar.class);
|
||||
new DefaultBeanRegistrar().register(adapter, env);
|
||||
BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("foo");
|
||||
assertThat(beanDefinition.getScope()).isEqualTo(AbstractBeanDefinition.SCOPE_DEFAULT);
|
||||
}
|
||||
|
||||
@Test
|
||||
void prototypeScope() {
|
||||
BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, PrototypeBeanRegistrar.class);
|
||||
new PrototypeBeanRegistrar().register(adapter, env);
|
||||
BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition("foo");
|
||||
assertThat(beanDefinition.getScope()).isEqualTo(AbstractBeanDefinition.SCOPE_PROTOTYPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultSupplier() {
|
||||
BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, DefaultBeanRegistrar.class);
|
||||
new DefaultBeanRegistrar().register(adapter, env);
|
||||
AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition)this.beanFactory.getBeanDefinition("foo");
|
||||
assertThat(beanDefinition.getInstanceSupplier()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void customSupplier() {
|
||||
BeanRegistryAdapter adapter = new BeanRegistryAdapter(this.beanFactory, this.beanFactory, SupplierBeanRegistrar.class);
|
||||
new SupplierBeanRegistrar().register(adapter, env);
|
||||
AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition)this.beanFactory.getBeanDefinition("foo");
|
||||
Supplier<?> supplier = beanDefinition.getInstanceSupplier();
|
||||
assertThat(supplier).isNotNull();
|
||||
assertThat(supplier.get()).isNotNull().isInstanceOf(Foo.class);
|
||||
}
|
||||
|
||||
|
||||
private static class DefaultBeanRegistrar implements BeanRegistrar {
|
||||
|
||||
@Override
|
||||
public void register(BeanRegistry registry, Environment env) {
|
||||
registry.registerBean("foo", Foo.class);
|
||||
}
|
||||
}
|
||||
|
||||
private static class BackgroundInitBeanRegistrar implements BeanRegistrar {
|
||||
|
||||
@Override
|
||||
public void register(BeanRegistry registry, Environment env) {
|
||||
registry.registerBean("foo", Foo.class, BeanRegistry.Spec::backgroundInit);
|
||||
}
|
||||
}
|
||||
|
||||
private static class CustomDescriptionBeanRegistrar implements BeanRegistrar {
|
||||
|
||||
@Override
|
||||
public void register(BeanRegistry registry, Environment env) {
|
||||
registry.registerBean("foo", Foo.class, spec -> spec.description("custom"));
|
||||
}
|
||||
}
|
||||
|
||||
private static class FallbackBeanRegistrar implements BeanRegistrar {
|
||||
|
||||
@Override
|
||||
public void register(BeanRegistry registry, Environment env) {
|
||||
registry.registerBean("foo", Foo.class, BeanRegistry.Spec::fallback);
|
||||
}
|
||||
}
|
||||
|
||||
private static class InfrastructureBeanRegistrar implements BeanRegistrar {
|
||||
|
||||
@Override
|
||||
public void register(BeanRegistry registry, Environment env) {
|
||||
registry.registerBean("foo", Foo.class, BeanRegistry.Spec::infrastructure);
|
||||
}
|
||||
}
|
||||
|
||||
private static class LazyInitBeanRegistrar implements BeanRegistrar {
|
||||
|
||||
@Override
|
||||
public void register(BeanRegistry registry, Environment env) {
|
||||
registry.registerBean("foo", Foo.class, BeanRegistry.Spec::lazyInit);
|
||||
}
|
||||
}
|
||||
|
||||
private static class NotAutowirableBeanRegistrar implements BeanRegistrar {
|
||||
|
||||
@Override
|
||||
public void register(BeanRegistry registry, Environment env) {
|
||||
registry.registerBean("foo", Foo.class, BeanRegistry.Spec::notAutowirable);
|
||||
}
|
||||
}
|
||||
|
||||
private static class CustomOrderBeanRegistrar implements BeanRegistrar {
|
||||
|
||||
@Override
|
||||
public void register(BeanRegistry registry, Environment env) {
|
||||
registry.registerBean("foo", Foo.class, spec -> spec.order(1));
|
||||
}
|
||||
}
|
||||
|
||||
private static class PrimaryBeanRegistrar implements BeanRegistrar {
|
||||
|
||||
@Override
|
||||
public void register(BeanRegistry registry, Environment env) {
|
||||
registry.registerBean("foo", Foo.class, BeanRegistry.Spec::primary);
|
||||
}
|
||||
}
|
||||
|
||||
private static class PrototypeBeanRegistrar implements BeanRegistrar {
|
||||
|
||||
@Override
|
||||
public void register(BeanRegistry registry, Environment env) {
|
||||
registry.registerBean("foo", Foo.class, BeanRegistry.Spec::prototype);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SupplierBeanRegistrar implements BeanRegistrar {
|
||||
|
||||
@Override
|
||||
public void register(BeanRegistry registry, Environment env) {
|
||||
registry.registerBean("foo", Foo.class, spec -> spec.supplier(context -> new Foo()));
|
||||
}
|
||||
}
|
||||
|
||||
private static class Foo {}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user