GenericApplicationContext offers Supplier-based registration with BeanDefinitionCustomizer callback

Issue: SPR-14832
This commit is contained in:
Juergen Hoeller
2016-12-23 12:26:47 +01:00
parent a86f89daa8
commit e788b8467d
6 changed files with 263 additions and 91 deletions

View File

@@ -19,8 +19,9 @@ package org.springframework.context.annotation;
import java.lang.annotation.Annotation;
import java.util.function.Supplier;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionCustomizer;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
@@ -139,9 +140,35 @@ public class AnnotatedBeanDefinitionReader {
* class-declared annotations.
* @param annotatedClass the class of the bean
*/
@SuppressWarnings("unchecked")
public void registerBean(Class<?> annotatedClass) {
registerBean(annotatedClass, null, null, (Class<? extends Annotation>[]) null);
doRegisterBean(annotatedClass, null, null, null);
}
/**
* Register a bean from the given bean class, deriving its metadata from
* class-declared annotations, using the given supplier for obtaining a new
* instance (possibly declared as a lambda expression or method reference).
* @param annotatedClass the class of the bean
* @param instanceSupplier a callback for creating an instance of the bean
* (may be {@code null})
* @since 5.0
*/
public <T> void registerBean(Class<T> annotatedClass, Supplier<T> instanceSupplier) {
doRegisterBean(annotatedClass, instanceSupplier, null, null);
}
/**
* Register a bean from the given bean class, deriving its metadata from
* class-declared annotations, using the given supplier for obtaining a new
* instance (possibly declared as a lambda expression or method reference).
* @param annotatedClass the class of the bean
* @param name an explicit name for the bean
* @param instanceSupplier a callback for creating an instance of the bean
* (may be {@code null})
* @since 5.0
*/
public <T> void registerBean(Class<T> annotatedClass, String name, Supplier<T> instanceSupplier) {
doRegisterBean(annotatedClass, instanceSupplier, name, null);
}
/**
@@ -153,7 +180,7 @@ public class AnnotatedBeanDefinitionReader {
*/
@SuppressWarnings("unchecked")
public void registerBean(Class<?> annotatedClass, Class<? extends Annotation>... qualifiers) {
registerBean(annotatedClass, null, null, qualifiers);
doRegisterBean(annotatedClass, null, null, qualifiers);
}
/**
@@ -166,23 +193,7 @@ public class AnnotatedBeanDefinitionReader {
*/
@SuppressWarnings("unchecked")
public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
registerBean(annotatedClass, null, name, qualifiers);
}
/**
* Register a bean from the given bean class, deriving its metadata from
* class-declared annotations, using the given supplier for obtaining a new
* instance (possibly declared as a lambda expression or method reference).
* @param annotatedClass the class of the bean
* @param instanceSupplier a callback for creating an instance of the bean
* (may be {@code null})
* @return the registered bean definition, or {@code null} if skipped due to
* a declared condition
* @since 5.0
*/
@SuppressWarnings("unchecked")
public <T> AnnotatedBeanDefinition registerBean(Class<T> annotatedClass, Supplier<T> instanceSupplier) {
return registerBean(annotatedClass, instanceSupplier, null, (Class<? extends Annotation>[]) null);
doRegisterBean(annotatedClass, null, name, qualifiers);
}
/**
@@ -194,23 +205,23 @@ public class AnnotatedBeanDefinitionReader {
* @param name an explicit name for the bean
* @param qualifiers specific qualifier annotations to consider, if any,
* in addition to qualifiers at the bean class level
* @return the registered bean definition, or {@code null} if skipped due to
* a declared condition
* @param definitionCustomizers one or more callbacks for customizing the
* factory's {@link BeanDefinition}, e.g. setting a lazy-init or primary flag
* @since 5.0
*/
@SuppressWarnings("unchecked")
public <T> AnnotatedBeanDefinition registerBean(Class<T> annotatedClass, Supplier<T> instanceSupplier,
String name, Class<? extends Annotation>... qualifiers) {
<T> void doRegisterBean(Class<T> annotatedClass, Supplier<T> instanceSupplier, String name,
Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return null;
return;
}
abd.setInstanceSupplier(instanceSupplier);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
@@ -225,11 +236,15 @@ public class AnnotatedBeanDefinitionReader {
}
}
}
if (definitionCustomizers != null) {
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
}
}
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
return abd;
}

View File

@@ -18,7 +18,7 @@ package org.springframework.context.annotation;
import java.util.function.Supplier;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionCustomizer;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.support.GenericApplicationContext;
@@ -181,36 +181,6 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex
// Convenient methods for registering individual beans
//---------------------------------------------------------------------
/**
* Register a bean from the given bean class, deriving its metadata from
* class-declared annotations, using the given supplier for obtaining a new
* instance (possibly declared as a lambda expression or method reference).
* <p>The bean name will be generated according to annotated component rules.
* @param annotatedClass the class of the bean
* @param instanceSupplier a callback for creating an instance of the bean
* @since 5.0
* @see #setBeanNameGenerator
*/
@SuppressWarnings("unchecked")
public <T> void registerBean(Class<T> annotatedClass, Supplier<T> instanceSupplier) {
registerBean(null, annotatedClass, instanceSupplier);
}
/**
* Register a bean from the given bean class, deriving its metadata from
* class-declared annotations, using the given supplier for obtaining a new
* instance (possibly declared as a lambda expression or method reference).
* @param beanName the name of the bean (may be {@code null})
* @param annotatedClass the class of the bean
* @param instanceSupplier a callback for creating an instance of the bean
* @since 5.0
*/
@SuppressWarnings("unchecked")
public <T> void registerBean(String beanName, Class<T> annotatedClass, Supplier<T> instanceSupplier) {
Assert.notNull(instanceSupplier, "Supplier must not be null");
this.reader.registerBean(annotatedClass, instanceSupplier, beanName);
}
/**
* Register a bean from the given bean class, deriving its metadata from
* class-declared annotations, and optionally providing explicit constructor
@@ -222,9 +192,7 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex
* specific ones, with the rest to be resolved through regular autowiring
* (may be {@code null} or empty)
* @since 5.0
* @see #setBeanNameGenerator
*/
@SuppressWarnings("unchecked")
public <T> void registerBean(Class<T> annotatedClass, Object... constructorArguments) {
registerBean(null, annotatedClass, constructorArguments);
}
@@ -241,14 +209,20 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex
* (may be {@code null} or empty)
* @since 5.0
*/
@SuppressWarnings("unchecked")
public <T> void registerBean(String beanName, Class<T> annotatedClass, Object... constructorArguments) {
AnnotatedBeanDefinition abd = this.reader.registerBean(annotatedClass, null, beanName);
if (constructorArguments != null) {
for (Object arg : constructorArguments) {
abd.getConstructorArgumentValues().addGenericArgumentValue(arg);
}
}
this.reader.doRegisterBean(annotatedClass, null, beanName, null,
bd -> {
for (Object arg : constructorArguments) {
bd.getConstructorArgumentValues().addGenericArgumentValue(arg);
}
});
}
@Override
public <T> void registerBean(String beanName, Class<T> beanClass, Supplier<T> supplier,
BeanDefinitionCustomizer... customizers) {
this.reader.doRegisterBean(beanClass, supplier, beanName, null, customizers);
}
}

View File

@@ -18,13 +18,16 @@ package org.springframework.context.support;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionCustomizer;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
@@ -350,4 +353,74 @@ public class GenericApplicationContext extends AbstractApplicationContext implem
return this.beanFactory.isAlias(beanName);
}
//---------------------------------------------------------------------
// Convenient methods for registering individual beans
//---------------------------------------------------------------------
/**
* Register a bean from the given bean class, optionally customizing its
* bean definition metadata (typically declared as a lambda expression
* or method reference).
* @param beanClass the class of the bean
* @param customizers one or more callbacks for customizing the
* factory's {@link BeanDefinition}, e.g. setting a lazy-init or primary flag
* @since 5.0
*/
public <T> void registerBean(Class<T> beanClass, BeanDefinitionCustomizer... customizers) {
registerBean(null, beanClass, null, customizers);
}
/**
* Register a bean from the given bean class, using the given supplier for
* obtaining a new instance (typically declared as a lambda expression or
* method reference), optionally customizing its bean definition metadata
* (again typically declared as a lambda expression or method reference).
* @param beanName the name of the bean (may be {@code null})
* @param beanClass the class of the bean
* @param customizers one or more callbacks for customizing the
* factory's {@link BeanDefinition}, e.g. setting a lazy-init or primary flag
* @since 5.0
*/
public <T> void registerBean(String beanName, Class<T> beanClass, BeanDefinitionCustomizer... customizers) {
registerBean(beanName, beanClass, null, customizers);
}
/**
* Register a bean from the given bean class, using the given supplier for
* obtaining a new instance (typically declared as a lambda expression or
* method reference), optionally customizing its bean definition metadata
* (again typically declared as a lambda expression or method reference).
* @param beanClass the class of the bean
* @param supplier a callback for creating an instance of the bean
* @param customizers one or more callbacks for customizing the
* factory's {@link BeanDefinition}, e.g. setting a lazy-init or primary flag
* @since 5.0
*/
public <T> void registerBean(Class<T> beanClass, Supplier<T> supplier, BeanDefinitionCustomizer... customizers) {
registerBean(null, beanClass, supplier, customizers);
}
/**
* Register a bean from the given bean class, using the given supplier for
* obtaining a new instance (typically declared as a lambda expression or
* method reference), optionally customizing its bean definition metadata
* (again typically declared as a lambda expression or method reference).
* @param beanName the name of the bean (may be {@code null})
* @param beanClass the class of the bean
* @param supplier a callback for creating an instance of the bean
* @param customizers one or more callbacks for customizing the
* factory's {@link BeanDefinition}, e.g. setting a lazy-init or primary flag
* @since 5.0
*/
public <T> void registerBean(String beanName, Class<T> beanClass, Supplier<T> supplier,
BeanDefinitionCustomizer... customizers) {
Assert.isTrue(beanName != null || beanClass != null, "Either bean name or bean class must be specified");
String nameToUse = (beanName != null ? beanName : beanClass.getName());
BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(beanClass, supplier).
applyCustomizers(customizers).getRawBeanDefinition();
registerBeanDefinition(nameToUse, beanDefinition);
}
}