diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java
index 4df284c308..389f19c9e4 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java
@@ -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 lazy-init
+ * singletons and objects created by FactoryBeans (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)
+ */
+ ObjectProvider getBeanProvider(Class 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 lazy-init
+ * singletons and objects created by FactoryBeans (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)
+ */
+ ObjectProvider 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}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
index 50e537d53e..6731ed5b45 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
@@ -354,14 +354,51 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
@Override
- public ObjectProvider getBeanProvider(Class requiredType) throws BeansException {
+ public ObjectProvider getBeanProvider(Class 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 ObjectProvider 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 ObjectProvider getBeanProvider(Class requiredType, boolean allowEagerInit) {
+ Assert.notNull(requiredType, "Required type must not be null");
+ return getBeanProvider(ResolvableType.forRawClass(requiredType), allowEagerInit);
+ }
+
+ @Override
+ public ObjectProvider getBeanProvider(ResolvableType requiredType, boolean allowEagerInit) {
return new BeanObjectProvider() {
@Override
public T getObject() throws BeansException {
@@ -426,14 +463,16 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
}
@Override
+ @SuppressWarnings("unchecked")
public Stream 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 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
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java
index 25c4cd59c5..a5430120df 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java
@@ -186,73 +186,12 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
@Override
public ObjectProvider getBeanProvider(Class requiredType) throws BeansException {
- return getBeanProvider(ResolvableType.forRawClass(requiredType));
+ return getBeanProvider(ResolvableType.forRawClass(requiredType), true);
}
- @SuppressWarnings("unchecked")
@Override
public ObjectProvider getBeanProvider(ResolvableType requiredType) {
- return new ObjectProvider() {
- @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 stream() {
- return Arrays.stream(getBeanNamesForType(requiredType)).map(name -> (T) getBean(name));
- }
- @Override
- public Stream 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 ObjectProvider getBeanProvider(Class requiredType, boolean allowEagerInit) {
+ return getBeanProvider(ResolvableType.forRawClass(requiredType), allowEagerInit);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public ObjectProvider getBeanProvider(ResolvableType requiredType, boolean allowEagerInit) {
+ return new ObjectProvider() {
+ @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 stream() {
+ return Arrays.stream(getBeanNamesForType(requiredType)).map(name -> (T) getBean(name));
+ }
+ @Override
+ public Stream orderedStream() {
+ return stream().sorted(OrderComparator.INSTANCE);
+ }
+ };
+ }
+
@Override
public String[] getBeanNamesForType(@Nullable ResolvableType type) {
return getBeanNamesForType(type, true, true);
diff --git a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java
index 951861aa85..b954d56159 100644
--- a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java
+++ b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java
@@ -1263,6 +1263,18 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
return getBeanFactory().getBeanDefinitionNames();
}
+ @Override
+ public ObjectProvider getBeanProvider(Class requiredType, boolean allowEagerInit) {
+ assertBeanFactoryActive();
+ return getBeanFactory().getBeanProvider(requiredType, allowEagerInit);
+ }
+
+ @Override
+ public ObjectProvider getBeanProvider(ResolvableType requiredType, boolean allowEagerInit) {
+ assertBeanFactoryActive();
+ return getBeanFactory().getBeanProvider(requiredType, allowEagerInit);
+ }
+
@Override
public String[] getBeanNamesForType(ResolvableType type) {
assertBeanFactoryActive();
diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StubWebApplicationContext.java b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StubWebApplicationContext.java
index b0ab174a8f..c5271e8d18 100644
--- a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StubWebApplicationContext.java
+++ b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StubWebApplicationContext.java
@@ -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 ObjectProvider getBeanProvider(Class requiredType, boolean allowEagerInit) {
+ return this.beanFactory.getBeanProvider(requiredType, allowEagerInit);
+ }
+
+ @Override
+ public ObjectProvider getBeanProvider(ResolvableType requiredType, boolean allowEagerInit) {
+ return this.beanFactory.getBeanProvider(requiredType, allowEagerInit);
+ }
+
@Override
public String[] getBeanNamesForType(@Nullable ResolvableType type) {
return this.beanFactory.getBeanNamesForType(type);