提交 2ee1ce61 编写于 作者: P Phillip Webb 提交者: Juergen Hoeller

Add missing variants of getBeanNamesForType

Update `ListableBeanFactory` and `BeanFactoryUtils` to add the missing
`getBeanNamesForType` methods that accept a `ResolvableType` rather
than a `Class`.

This completes the work started in 778a0194.

Closes gh-23335
上级 30132b42
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 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.
......@@ -172,6 +172,44 @@ public abstract class BeanFactoryUtils {
return result;
}
/**
* Get all bean names for the given type, including those defined in ancestor
* factories. Will return unique names in case of overridden bean definitions.
* <p>Does consider objects created by FactoryBeans if the "allowEagerInit"
* flag is set, which means that FactoryBeans will get initialized. If the
* object created by the FactoryBean doesn't match, the raw FactoryBean itself
* will be matched against the type. If "allowEagerInit" is not set,
* only raw FactoryBeans will be checked (which doesn't require initialization
* of each FactoryBean).
* @param lbf the bean factory
* @param includeNonSingletons whether to include prototype or scoped beans too
* or just singletons (also applies to FactoryBeans)
* @param allowEagerInit whether to 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. Note that FactoryBeans need to be
* eagerly initialized to determine their type: So be aware that passing in "true"
* for this flag will initialize FactoryBeans and "factory-bean" references.
* @param type the type that beans must match (as a {@code ResolvableType})
* @return the array of matching bean names, or an empty array if none
* @since 5.2
* @see ListableBeanFactory#getBeanNamesForType(ResolvableType, boolean, boolean)
*/
public static String[] beanNamesForTypeIncludingAncestors(
ListableBeanFactory lbf, ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
Assert.notNull(lbf, "ListableBeanFactory must not be null");
String[] result = lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
if (lbf instanceof HierarchicalBeanFactory) {
HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf;
if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
String[] parentResult = beanNamesForTypeIncludingAncestors(
(ListableBeanFactory) hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit);
result = mergeNamesWithParent(result, parentResult, hbf);
}
}
return result;
}
/**
* Get all bean names for the given type, including those defined in ancestor
* factories. Will return unique names in case of overridden bean definitions.
......
......@@ -116,6 +116,40 @@ public interface ListableBeanFactory extends BeanFactory {
*/
String[] getBeanNamesForType(ResolvableType type);
/**
* Return the names of beans matching the given type (including subclasses),
* judging from either bean definitions or the value of {@code getObjectType}
* in the case of FactoryBeans.
* <p><b>NOTE: This method introspects top-level beans only.</b> It does <i>not</i>
* check nested beans which might match the specified type as well.
* <p>Does consider objects created by FactoryBeans if the "allowEagerInit" flag is set,
* which means that FactoryBeans will get initialized. If the object created by the
* FactoryBean doesn't match, the raw FactoryBean itself will be matched against the
* type. If "allowEagerInit" is not set, only raw FactoryBeans will be checked
* (which doesn't require initialization of each FactoryBean).
* <p>Does not consider any hierarchy this factory may participate in.
* Use BeanFactoryUtils' {@code beanNamesForTypeIncludingAncestors}
* to include beans in ancestor factories too.
* <p>Note: Does <i>not</i> ignore singleton beans that have been registered
* by other means than bean definitions.
* <p>Bean names returned by this method should always return bean names <i>in the
* order of definition</i> in the backend configuration, as far as possible.
* @param type the generically typed class or interface to match
* @param includeNonSingletons whether to include prototype or scoped beans too
* or just singletons (also applies to FactoryBeans)
* @param allowEagerInit whether to 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. Note that FactoryBeans need to be
* eagerly initialized to determine their type: So be aware that passing in "true"
* for this flag will initialize FactoryBeans and "factory-bean" references.
* @return the names of beans (or objects created by FactoryBeans) matching
* the given object type (including subclasses), or an empty array if none
* @since 5.2
* @see FactoryBean#getObjectType
* @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors(ListableBeanFactory, ResolvableType, boolean, boolean)
*/
String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit);
/**
* Return the names of beans matching the given type (including subclasses),
* judging from either bean definitions or the value of {@code getObjectType}
......
......@@ -463,12 +463,17 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
@Override
public String[] getBeanNamesForType(ResolvableType type) {
return getBeanNamesForType(type, true, true);
}
@Override
public String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
Class<?> resolved = type.resolve();
if (resolved != null && !type.hasGenerics()) {
return getBeanNamesForType(resolved, true, true);
return getBeanNamesForType(resolved, includeNonSingletons, includeNonSingletons);
}
else {
return doGetBeanNamesForType(type, true, true);
return doGetBeanNamesForType(type, includeNonSingletons, includeNonSingletons);
}
}
......
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 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.
......@@ -329,26 +329,32 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
@Override
public String[] getBeanNamesForType(@Nullable ResolvableType type) {
boolean isFactoryType = false;
if (type != null) {
Class<?> resolved = type.resolve();
if (resolved != null && FactoryBean.class.isAssignableFrom(resolved)) {
isFactoryType = true;
}
}
return getBeanNamesForType(type, true, true);
}
@Override
public String[] getBeanNamesForType(@Nullable ResolvableType type,
boolean includeNonSingletons, boolean allowEagerInit) {
Class<?> resolved = (type != null ? type.resolve() : null);
boolean isFactoryType = resolved != null && FactoryBean.class.isAssignableFrom(resolved);
List<String> matches = new ArrayList<>();
for (Map.Entry<String, Object> entry : this.beans.entrySet()) {
String name = entry.getKey();
String beanName = entry.getKey();
Object beanInstance = entry.getValue();
if (beanInstance instanceof FactoryBean && !isFactoryType) {
Class<?> objectType = ((FactoryBean<?>) beanInstance).getObjectType();
if (objectType != null && (type == null || type.isAssignableFrom(objectType))) {
matches.add(name);
FactoryBean<?> factoryBean = (FactoryBean<?>) beanInstance;
Class<?> objectType = factoryBean.getObjectType();
if ((includeNonSingletons || factoryBean.isSingleton()) &&
objectType != null && (type == null || type.isAssignableFrom(objectType))) {
matches.add(beanName);
}
}
else {
if (type == null || type.isInstance(beanInstance)) {
matches.add(name);
matches.add(beanName);
}
}
}
......@@ -362,7 +368,7 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
@Override
public String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
return getBeanNamesForType(ResolvableType.forClass(type));
return getBeanNamesForType(ResolvableType.forClass(type), includeNonSingletons, allowEagerInit);
}
@Override
......
......@@ -1751,6 +1751,8 @@ public class DefaultListableBeanFactoryTests {
assertThat(lbf.getBeanNamesForType(ConstructorDependencyFactoryBean.class).length).isEqualTo(1);
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, Object.class)).length).isEqualTo(1);
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, String.class)).length).isEqualTo(0);
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, Object.class), true, true).length).isEqualTo(1);
assertThat(lbf.getBeanNamesForType(ResolvableType.forClassWithGenerics(FactoryBean.class, String.class), true, true).length).isEqualTo(0);
}
private RootBeanDefinition createConstructorDependencyBeanDefinition(int age) {
......
......@@ -1208,6 +1208,12 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
return getBeanFactory().getBeanNamesForType(type);
}
@Override
public String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
assertBeanFactoryActive();
return getBeanFactory().getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
}
@Override
public String[] getBeanNamesForType(@Nullable Class<?> type) {
assertBeanFactoryActive();
......
......@@ -251,6 +251,11 @@ class StubWebApplicationContext implements WebApplicationContext {
return this.beanFactory.getBeanNamesForType(type);
}
@Override
public String[] getBeanNamesForType(@Nullable ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
return this.beanFactory.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
}
@Override
public String[] getBeanNamesForType(@Nullable Class<?> type) {
return this.beanFactory.getBeanNamesForType(type);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册