Skip to content

Commit b345019

Browse files
committed
Introduce getBeanProvider variants with allowEagerInit flag
Closes gh-25559
1 parent 392f51c commit b345019

File tree

5 files changed

+179
-98
lines changed

5 files changed

+179
-98
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/ListableBeanFactory.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,43 @@ public interface ListableBeanFactory extends BeanFactory {
8787
*/
8888
String[] getBeanDefinitionNames();
8989

90+
/**
91+
* Return a provider for the specified bean, allowing for lazy on-demand retrieval
92+
* of instances, including availability and uniqueness options.
93+
* @param requiredType type the bean must match; can be an interface or superclass
94+
* @param allowEagerInit whether stream-based access may initialize <i>lazy-init
95+
* singletons</i> and <i>objects created by FactoryBeans</i> (or by factory methods
96+
* with a "factory-bean" reference) for the type check
97+
* @return a corresponding provider handle
98+
* @since 5.3
99+
* @see #getBeanProvider(ResolvableType, boolean)
100+
* @see #getBeanProvider(Class)
101+
* @see #getBeansOfType(Class, boolean, boolean)
102+
* @see #getBeanNamesForType(Class, boolean, boolean)
103+
*/
104+
<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType, boolean allowEagerInit);
105+
106+
/**
107+
* Return a provider for the specified bean, allowing for lazy on-demand retrieval
108+
* of instances, including availability and uniqueness options.
109+
* @param requiredType type the bean must match; can be a generic type declaration.
110+
* Note that collection types are not supported here, in contrast to reflective
111+
* injection points. For programmatically retrieving a list of beans matching a
112+
* specific type, specify the actual bean type as an argument here and subsequently
113+
* use {@link ObjectProvider#orderedStream()} or its lazy streaming/iteration options.
114+
* @param allowEagerInit whether stream-based access may initialize <i>lazy-init
115+
* singletons</i> and <i>objects created by FactoryBeans</i> (or by factory methods
116+
* with a "factory-bean" reference) for the type check
117+
* @return a corresponding provider handle
118+
* @since 5.3
119+
* @see #getBeanProvider(ResolvableType)
120+
* @see ObjectProvider#iterator()
121+
* @see ObjectProvider#stream()
122+
* @see ObjectProvider#orderedStream()
123+
* @see #getBeanNamesForType(ResolvableType, boolean, boolean)
124+
*/
125+
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType, boolean allowEagerInit);
126+
90127
/**
91128
* Return the names of beans matching the given type (including subclasses),
92129
* judging from either bean definitions or the value of {@code getObjectType}

spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java

Lines changed: 46 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -354,14 +354,51 @@ public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws Bea
354354
}
355355

356356
@Override
357-
public <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType) throws BeansException {
357+
public <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType) {
358358
Assert.notNull(requiredType, "Required type must not be null");
359-
return getBeanProvider(ResolvableType.forRawClass(requiredType));
359+
return getBeanProvider(ResolvableType.forRawClass(requiredType), true);
360360
}
361361

362-
@SuppressWarnings("unchecked")
363362
@Override
364363
public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType) {
364+
return getBeanProvider(requiredType, true);
365+
}
366+
367+
368+
//---------------------------------------------------------------------
369+
// Implementation of ListableBeanFactory interface
370+
//---------------------------------------------------------------------
371+
372+
@Override
373+
public boolean containsBeanDefinition(String beanName) {
374+
Assert.notNull(beanName, "Bean name must not be null");
375+
return this.beanDefinitionMap.containsKey(beanName);
376+
}
377+
378+
@Override
379+
public int getBeanDefinitionCount() {
380+
return this.beanDefinitionMap.size();
381+
}
382+
383+
@Override
384+
public String[] getBeanDefinitionNames() {
385+
String[] frozenNames = this.frozenBeanDefinitionNames;
386+
if (frozenNames != null) {
387+
return frozenNames.clone();
388+
}
389+
else {
390+
return StringUtils.toStringArray(this.beanDefinitionNames);
391+
}
392+
}
393+
394+
@Override
395+
public <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType, boolean allowEagerInit) {
396+
Assert.notNull(requiredType, "Required type must not be null");
397+
return getBeanProvider(ResolvableType.forRawClass(requiredType), allowEagerInit);
398+
}
399+
400+
@Override
401+
public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType, boolean allowEagerInit) {
365402
return new BeanObjectProvider<T>() {
366403
@Override
367404
public T getObject() throws BeansException {
@@ -426,14 +463,16 @@ public void ifUnique(Consumer<T> dependencyConsumer) throws BeansException {
426463
}
427464
}
428465
@Override
466+
@SuppressWarnings("unchecked")
429467
public Stream<T> stream() {
430-
return Arrays.stream(getBeanNamesForTypedStream(requiredType))
468+
return Arrays.stream(getBeanNamesForTypedStream(requiredType, allowEagerInit))
431469
.map(name -> (T) getBean(name))
432470
.filter(bean -> !(bean instanceof NullBean));
433471
}
434472
@Override
473+
@SuppressWarnings("unchecked")
435474
public Stream<T> orderedStream() {
436-
String[] beanNames = getBeanNamesForTypedStream(requiredType);
475+
String[] beanNames = getBeanNamesForTypedStream(requiredType, allowEagerInit);
437476
if (beanNames.length == 0) {
438477
return Stream.empty();
439478
}
@@ -472,35 +511,8 @@ else if (parent != null) {
472511
return null;
473512
}
474513

475-
private String[] getBeanNamesForTypedStream(ResolvableType requiredType) {
476-
return BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType);
477-
}
478-
479-
480-
//---------------------------------------------------------------------
481-
// Implementation of ListableBeanFactory interface
482-
//---------------------------------------------------------------------
483-
484-
@Override
485-
public boolean containsBeanDefinition(String beanName) {
486-
Assert.notNull(beanName, "Bean name must not be null");
487-
return this.beanDefinitionMap.containsKey(beanName);
488-
}
489-
490-
@Override
491-
public int getBeanDefinitionCount() {
492-
return this.beanDefinitionMap.size();
493-
}
494-
495-
@Override
496-
public String[] getBeanDefinitionNames() {
497-
String[] frozenNames = this.frozenBeanDefinitionNames;
498-
if (frozenNames != null) {
499-
return frozenNames.clone();
500-
}
501-
else {
502-
return StringUtils.toStringArray(this.beanDefinitionNames);
503-
}
514+
private String[] getBeanNamesForTypedStream(ResolvableType requiredType, boolean allowEagerInit) {
515+
return BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType, true, allowEagerInit);
504516
}
505517

506518
@Override

spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java

Lines changed: 73 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -186,73 +186,12 @@ public <T> T getBean(Class<T> requiredType, Object... args) throws BeansExceptio
186186

187187
@Override
188188
public <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType) throws BeansException {
189-
return getBeanProvider(ResolvableType.forRawClass(requiredType));
189+
return getBeanProvider(ResolvableType.forRawClass(requiredType), true);
190190
}
191191

192-
@SuppressWarnings("unchecked")
193192
@Override
194193
public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType) {
195-
return new ObjectProvider<T>() {
196-
@Override
197-
public T getObject() throws BeansException {
198-
String[] beanNames = getBeanNamesForType(requiredType);
199-
if (beanNames.length == 1) {
200-
return (T) getBean(beanNames[0], requiredType);
201-
}
202-
else if (beanNames.length > 1) {
203-
throw new NoUniqueBeanDefinitionException(requiredType, beanNames);
204-
}
205-
else {
206-
throw new NoSuchBeanDefinitionException(requiredType);
207-
}
208-
}
209-
@Override
210-
public T getObject(Object... args) throws BeansException {
211-
String[] beanNames = getBeanNamesForType(requiredType);
212-
if (beanNames.length == 1) {
213-
return (T) getBean(beanNames[0], args);
214-
}
215-
else if (beanNames.length > 1) {
216-
throw new NoUniqueBeanDefinitionException(requiredType, beanNames);
217-
}
218-
else {
219-
throw new NoSuchBeanDefinitionException(requiredType);
220-
}
221-
}
222-
@Override
223-
@Nullable
224-
public T getIfAvailable() throws BeansException {
225-
String[] beanNames = getBeanNamesForType(requiredType);
226-
if (beanNames.length == 1) {
227-
return (T) getBean(beanNames[0]);
228-
}
229-
else if (beanNames.length > 1) {
230-
throw new NoUniqueBeanDefinitionException(requiredType, beanNames);
231-
}
232-
else {
233-
return null;
234-
}
235-
}
236-
@Override
237-
@Nullable
238-
public T getIfUnique() throws BeansException {
239-
String[] beanNames = getBeanNamesForType(requiredType);
240-
if (beanNames.length == 1) {
241-
return (T) getBean(beanNames[0]);
242-
}
243-
else {
244-
return null;
245-
}
246-
}
247-
@Override
248-
public Stream<T> stream() {
249-
return Arrays.stream(getBeanNamesForType(requiredType)).map(name -> (T) getBean(name));
250-
}
251-
@Override
252-
public Stream<T> orderedStream() {
253-
return stream().sorted(OrderComparator.INSTANCE);
254-
}
255-
};
194+
return getBeanProvider(requiredType, true);
256195
}
257196

258197
@Override
@@ -337,6 +276,77 @@ public String[] getBeanDefinitionNames() {
337276
return StringUtils.toStringArray(this.beans.keySet());
338277
}
339278

279+
@Override
280+
public <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType, boolean allowEagerInit) {
281+
return getBeanProvider(ResolvableType.forRawClass(requiredType), allowEagerInit);
282+
}
283+
284+
@SuppressWarnings("unchecked")
285+
@Override
286+
public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType, boolean allowEagerInit) {
287+
return new ObjectProvider<T>() {
288+
@Override
289+
public T getObject() throws BeansException {
290+
String[] beanNames = getBeanNamesForType(requiredType);
291+
if (beanNames.length == 1) {
292+
return (T) getBean(beanNames[0], requiredType);
293+
}
294+
else if (beanNames.length > 1) {
295+
throw new NoUniqueBeanDefinitionException(requiredType, beanNames);
296+
}
297+
else {
298+
throw new NoSuchBeanDefinitionException(requiredType);
299+
}
300+
}
301+
@Override
302+
public T getObject(Object... args) throws BeansException {
303+
String[] beanNames = getBeanNamesForType(requiredType);
304+
if (beanNames.length == 1) {
305+
return (T) getBean(beanNames[0], args);
306+
}
307+
else if (beanNames.length > 1) {
308+
throw new NoUniqueBeanDefinitionException(requiredType, beanNames);
309+
}
310+
else {
311+
throw new NoSuchBeanDefinitionException(requiredType);
312+
}
313+
}
314+
@Override
315+
@Nullable
316+
public T getIfAvailable() throws BeansException {
317+
String[] beanNames = getBeanNamesForType(requiredType);
318+
if (beanNames.length == 1) {
319+
return (T) getBean(beanNames[0]);
320+
}
321+
else if (beanNames.length > 1) {
322+
throw new NoUniqueBeanDefinitionException(requiredType, beanNames);
323+
}
324+
else {
325+
return null;
326+
}
327+
}
328+
@Override
329+
@Nullable
330+
public T getIfUnique() throws BeansException {
331+
String[] beanNames = getBeanNamesForType(requiredType);
332+
if (beanNames.length == 1) {
333+
return (T) getBean(beanNames[0]);
334+
}
335+
else {
336+
return null;
337+
}
338+
}
339+
@Override
340+
public Stream<T> stream() {
341+
return Arrays.stream(getBeanNamesForType(requiredType)).map(name -> (T) getBean(name));
342+
}
343+
@Override
344+
public Stream<T> orderedStream() {
345+
return stream().sorted(OrderComparator.INSTANCE);
346+
}
347+
};
348+
}
349+
340350
@Override
341351
public String[] getBeanNamesForType(@Nullable ResolvableType type) {
342352
return getBeanNamesForType(type, true, true);

spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1263,6 +1263,18 @@ public String[] getBeanDefinitionNames() {
12631263
return getBeanFactory().getBeanDefinitionNames();
12641264
}
12651265

1266+
@Override
1267+
public <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType, boolean allowEagerInit) {
1268+
assertBeanFactoryActive();
1269+
return getBeanFactory().getBeanProvider(requiredType, allowEagerInit);
1270+
}
1271+
1272+
@Override
1273+
public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType, boolean allowEagerInit) {
1274+
assertBeanFactoryActive();
1275+
return getBeanFactory().getBeanProvider(requiredType, allowEagerInit);
1276+
}
1277+
12661278
@Override
12671279
public String[] getBeanNamesForType(ResolvableType type) {
12681280
assertBeanFactoryActive();

spring-test/src/main/java/org/springframework/test/web/servlet/setup/StubWebApplicationContext.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -252,6 +252,16 @@ public String[] getBeanDefinitionNames() {
252252
return this.beanFactory.getBeanDefinitionNames();
253253
}
254254

255+
@Override
256+
public <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType, boolean allowEagerInit) {
257+
return this.beanFactory.getBeanProvider(requiredType, allowEagerInit);
258+
}
259+
260+
@Override
261+
public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType, boolean allowEagerInit) {
262+
return this.beanFactory.getBeanProvider(requiredType, allowEagerInit);
263+
}
264+
255265
@Override
256266
public String[] getBeanNamesForType(@Nullable ResolvableType type) {
257267
return this.beanFactory.getBeanNamesForType(type);

0 commit comments

Comments
 (0)