Introduce getBeanProvider variants with allowEagerInit flag

Closes gh-25559
This commit is contained in:
Juergen Hoeller 2020-08-07 12:07:13 +02:00
parent 392f51cdd6
commit b345019415
5 changed files with 179 additions and 98 deletions

View File

@ -87,6 +87,43 @@ public interface ListableBeanFactory extends BeanFactory {
*/
String[] getBeanDefinitionNames();
/**
* Return a provider for the specified bean, allowing for lazy on-demand retrieval
* of instances, including availability and uniqueness options.
* @param requiredType type the bean must match; can be an interface or superclass
* @param allowEagerInit whether stream-based access may initialize <i>lazy-init
* singletons</i> and <i>objects created by FactoryBeans</i> (or by factory methods
* with a "factory-bean" reference) for the type check
* @return a corresponding provider handle
* @since 5.3
* @see #getBeanProvider(ResolvableType, boolean)
* @see #getBeanProvider(Class)
* @see #getBeansOfType(Class, boolean, boolean)
* @see #getBeanNamesForType(Class, boolean, boolean)
*/
<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType, boolean allowEagerInit);
/**
* Return a provider for the specified bean, allowing for lazy on-demand retrieval
* of instances, including availability and uniqueness options.
* @param requiredType type the bean must match; can be a generic type declaration.
* Note that collection types 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.
* @param allowEagerInit whether stream-based access may initialize <i>lazy-init
* singletons</i> and <i>objects created by FactoryBeans</i> (or by factory methods
* with a "factory-bean" reference) for the type check
* @return a corresponding provider handle
* @since 5.3
* @see #getBeanProvider(ResolvableType)
* @see ObjectProvider#iterator()
* @see ObjectProvider#stream()
* @see ObjectProvider#orderedStream()
* @see #getBeanNamesForType(ResolvableType, boolean, boolean)
*/
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType, boolean allowEagerInit);
/**
* Return the names of beans matching the given type (including subclasses),
* judging from either bean definitions or the value of {@code getObjectType}

View File

@ -354,14 +354,51 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
@Override
public <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType) throws BeansException {
public <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType) {
Assert.notNull(requiredType, "Required type must not be null");
return getBeanProvider(ResolvableType.forRawClass(requiredType));
return getBeanProvider(ResolvableType.forRawClass(requiredType), true);
}
@SuppressWarnings("unchecked")
@Override
public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType) {
return getBeanProvider(requiredType, true);
}
//---------------------------------------------------------------------
// Implementation of ListableBeanFactory interface
//---------------------------------------------------------------------
@Override
public boolean containsBeanDefinition(String beanName) {
Assert.notNull(beanName, "Bean name must not be null");
return this.beanDefinitionMap.containsKey(beanName);
}
@Override
public int getBeanDefinitionCount() {
return this.beanDefinitionMap.size();
}
@Override
public String[] getBeanDefinitionNames() {
String[] frozenNames = this.frozenBeanDefinitionNames;
if (frozenNames != null) {
return frozenNames.clone();
}
else {
return StringUtils.toStringArray(this.beanDefinitionNames);
}
}
@Override
public <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType, boolean allowEagerInit) {
Assert.notNull(requiredType, "Required type must not be null");
return getBeanProvider(ResolvableType.forRawClass(requiredType), allowEagerInit);
}
@Override
public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType, boolean allowEagerInit) {
return new BeanObjectProvider<T>() {
@Override
public T getObject() throws BeansException {
@ -426,14 +463,16 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
}
@Override
@SuppressWarnings("unchecked")
public Stream<T> stream() {
return Arrays.stream(getBeanNamesForTypedStream(requiredType))
return Arrays.stream(getBeanNamesForTypedStream(requiredType, allowEagerInit))
.map(name -> (T) getBean(name))
.filter(bean -> !(bean instanceof NullBean));
}
@Override
@SuppressWarnings("unchecked")
public Stream<T> orderedStream() {
String[] beanNames = getBeanNamesForTypedStream(requiredType);
String[] beanNames = getBeanNamesForTypedStream(requiredType, allowEagerInit);
if (beanNames.length == 0) {
return Stream.empty();
}
@ -472,35 +511,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
return null;
}
private String[] getBeanNamesForTypedStream(ResolvableType requiredType) {
return BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType);
}
//---------------------------------------------------------------------
// Implementation of ListableBeanFactory interface
//---------------------------------------------------------------------
@Override
public boolean containsBeanDefinition(String beanName) {
Assert.notNull(beanName, "Bean name must not be null");
return this.beanDefinitionMap.containsKey(beanName);
}
@Override
public int getBeanDefinitionCount() {
return this.beanDefinitionMap.size();
}
@Override
public String[] getBeanDefinitionNames() {
String[] frozenNames = this.frozenBeanDefinitionNames;
if (frozenNames != null) {
return frozenNames.clone();
}
else {
return StringUtils.toStringArray(this.beanDefinitionNames);
}
private String[] getBeanNamesForTypedStream(ResolvableType requiredType, boolean allowEagerInit) {
return BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType, true, allowEagerInit);
}
@Override

View File

@ -186,73 +186,12 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
@Override
public <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType) throws BeansException {
return getBeanProvider(ResolvableType.forRawClass(requiredType));
return getBeanProvider(ResolvableType.forRawClass(requiredType), true);
}
@SuppressWarnings("unchecked")
@Override
public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType) {
return new ObjectProvider<T>() {
@Override
public T getObject() throws BeansException {
String[] beanNames = getBeanNamesForType(requiredType);
if (beanNames.length == 1) {
return (T) getBean(beanNames[0], requiredType);
}
else if (beanNames.length > 1) {
throw new NoUniqueBeanDefinitionException(requiredType, beanNames);
}
else {
throw new NoSuchBeanDefinitionException(requiredType);
}
}
@Override
public T getObject(Object... args) throws BeansException {
String[] beanNames = getBeanNamesForType(requiredType);
if (beanNames.length == 1) {
return (T) getBean(beanNames[0], args);
}
else if (beanNames.length > 1) {
throw new NoUniqueBeanDefinitionException(requiredType, beanNames);
}
else {
throw new NoSuchBeanDefinitionException(requiredType);
}
}
@Override
@Nullable
public T getIfAvailable() throws BeansException {
String[] beanNames = getBeanNamesForType(requiredType);
if (beanNames.length == 1) {
return (T) getBean(beanNames[0]);
}
else if (beanNames.length > 1) {
throw new NoUniqueBeanDefinitionException(requiredType, beanNames);
}
else {
return null;
}
}
@Override
@Nullable
public T getIfUnique() throws BeansException {
String[] beanNames = getBeanNamesForType(requiredType);
if (beanNames.length == 1) {
return (T) getBean(beanNames[0]);
}
else {
return null;
}
}
@Override
public Stream<T> stream() {
return Arrays.stream(getBeanNamesForType(requiredType)).map(name -> (T) getBean(name));
}
@Override
public Stream<T> orderedStream() {
return stream().sorted(OrderComparator.INSTANCE);
}
};
return getBeanProvider(requiredType, true);
}
@Override
@ -337,6 +276,77 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
return StringUtils.toStringArray(this.beans.keySet());
}
@Override
public <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType, boolean allowEagerInit) {
return getBeanProvider(ResolvableType.forRawClass(requiredType), allowEagerInit);
}
@SuppressWarnings("unchecked")
@Override
public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType, boolean allowEagerInit) {
return new ObjectProvider<T>() {
@Override
public T getObject() throws BeansException {
String[] beanNames = getBeanNamesForType(requiredType);
if (beanNames.length == 1) {
return (T) getBean(beanNames[0], requiredType);
}
else if (beanNames.length > 1) {
throw new NoUniqueBeanDefinitionException(requiredType, beanNames);
}
else {
throw new NoSuchBeanDefinitionException(requiredType);
}
}
@Override
public T getObject(Object... args) throws BeansException {
String[] beanNames = getBeanNamesForType(requiredType);
if (beanNames.length == 1) {
return (T) getBean(beanNames[0], args);
}
else if (beanNames.length > 1) {
throw new NoUniqueBeanDefinitionException(requiredType, beanNames);
}
else {
throw new NoSuchBeanDefinitionException(requiredType);
}
}
@Override
@Nullable
public T getIfAvailable() throws BeansException {
String[] beanNames = getBeanNamesForType(requiredType);
if (beanNames.length == 1) {
return (T) getBean(beanNames[0]);
}
else if (beanNames.length > 1) {
throw new NoUniqueBeanDefinitionException(requiredType, beanNames);
}
else {
return null;
}
}
@Override
@Nullable
public T getIfUnique() throws BeansException {
String[] beanNames = getBeanNamesForType(requiredType);
if (beanNames.length == 1) {
return (T) getBean(beanNames[0]);
}
else {
return null;
}
}
@Override
public Stream<T> stream() {
return Arrays.stream(getBeanNamesForType(requiredType)).map(name -> (T) getBean(name));
}
@Override
public Stream<T> orderedStream() {
return stream().sorted(OrderComparator.INSTANCE);
}
};
}
@Override
public String[] getBeanNamesForType(@Nullable ResolvableType type) {
return getBeanNamesForType(type, true, true);

View File

@ -1263,6 +1263,18 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
return getBeanFactory().getBeanDefinitionNames();
}
@Override
public <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType, boolean allowEagerInit) {
assertBeanFactoryActive();
return getBeanFactory().getBeanProvider(requiredType, allowEagerInit);
}
@Override
public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType, boolean allowEagerInit) {
assertBeanFactoryActive();
return getBeanFactory().getBeanProvider(requiredType, allowEagerInit);
}
@Override
public String[] getBeanNamesForType(ResolvableType type) {
assertBeanFactoryActive();

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
@ -252,6 +252,16 @@ class StubWebApplicationContext implements WebApplicationContext {
return this.beanFactory.getBeanDefinitionNames();
}
@Override
public <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType, boolean allowEagerInit) {
return this.beanFactory.getBeanProvider(requiredType, allowEagerInit);
}
@Override
public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType, boolean allowEagerInit) {
return this.beanFactory.getBeanProvider(requiredType, allowEagerInit);
}
@Override
public String[] getBeanNamesForType(@Nullable ResolvableType type) {
return this.beanFactory.getBeanNamesForType(type);