java Spring 按类型列出 bean

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1450145/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 16:34:37  来源:igfitidea点击:

Spring list beans by type

javaspringautowired

提问by Jeff Storey

Is there a way in Spring that I can auto populate a list with all of beans of a type AND any of its subtypes? I have a setter method that looks like:

在 Spring 中有没有一种方法可以让我自动填充一个类型的所有 bean 及其任何子类型的列表?我有一个如下所示的 setter 方法:

setMyProp(List<MyType> list)

And I would like to autowire in any beans of MyType and all subclasses of MyType.

我想在 MyType 的任何 bean 和 MyType 的所有子类中自动装配。

Thanks, Jeff

谢谢,杰夫

回答by skaffman

Yup, you can do this. The spring docs say:

是的,你可以这样做。春季文档说:

It is also possible to provide all beans of a particular type from the ApplicationContext by adding the annotation to a field or method that expects an array of that type.

通过将注解添加到需要该类型数组的字段或方法,还可以从 ApplicationContext 提供特定类型的所有 bean。

Note that it says you need to expect an array, not a list. This makes sense, because generic type erasure means a list may not work at runtime. However, take the following unit test, which works:

请注意,它说您需要一个数组,而不是一个列表。这是有道理的,因为泛型类型擦除意味着列表可能在运行时不起作用。但是,请进行以下单元测试,该测试有效:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">  

    <bean class="test.Test.TypeB"/>
    <bean class="test.Test.TypeC"/>
    <bean class="test.Test.TypeD"/>
</beans>

and this unit test:

这个单元测试:

package test;

@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class Test {

    private @Autowired List<TypeA> beans;

    @org.junit.Test
    public void test() {
        assertNotNull(beans);
        assertEquals(2, beans.size());
        for (TypeA bean : beans) {
            assertTrue(bean instanceof TypeA);
        }
    }       

    public static interface TypeA {}
    public static class TypeB implements TypeA {}
    public static class TypeC extends TypeB {}
    public static class TypeD {}

}

So officially, you're supposed to autowire TypeA[], not List<TypeA>, but the List works good.

因此,正式地,您应该自动装配TypeA[],而不是List<TypeA>,但是 List 运行良好。

回答by tangens

If it's acceptable to fill the list from your application code and not from within the bean definition file you could use the org.springframework.beans.factory.xml.XmlBeanFactoryand ask it "getBeansOfType( MyType.class )". This gives you all beans of type (and subtype) of MyType.

如果从您的应用程序代码而不是从 bean 定义文件中填充列表是可以接受的,您可以使用org.springframework.beans.factory.xml.XmlBeanFactory并询问它“ getBeansOfType( MyType.class )”。这为您提供了所有类型(和子类型)的MyType.

回答by Oliver Drotbohm

If you can use @Autowiredinside the code to be populated you can safely use the way mentioned by skaffman. If you insist on XML configuration there is a small library called Herato achieve this. Esentially configuration of a scenario described by you looks like this:

如果您可以 @Autowired在要填充的代码中使用,则可以安全地使用 skaffman 提到的方式。如果您坚持使用 XML 配置,则有一个名为Hera的小型库可以实现这一点。您描述的场景的基本配置如下所示:

<bean id="client" class="..">
    <property name="injectDynamicListHere">
        <hera:list class="my.custom.SuperType" />
    </property>
</bean>

This will inject all top-level Spring beans implementing SuperTypeas Listinto the client bean.

这会将实现SuperTypeas 的所有顶级 Spring beanList注入客户端 bean。

回答by Grigory Kislin

Due to legacy code and missing @Autowired I solve it like:

由于遗留代码和缺少@Autowired,我将其解决如下:

MyBean implements ApplicationContextAware{

  @Override
  public void setApplicationContext(ApplicationContext ctx) throws BeansException {
    final Map<String, HttpRequestHandlerTemplate> beansOfType = ctx.getBeansOfType(RequiredBean.class);
    ...
}

回答by cletus

Short answer: no.

简短的回答:没有。

Long answer: Java generics work by type erasure, meaning that at runtime that parameter is simply a List, not a List of a generic type. As such you can't figure out that it is meant to be of parameter type MyType so it wouldn't be possible to implement this behaviour.

长答案:Java 泛型通过类型擦除工作,这意味着在运行时该参数只是一个 List,而不是泛型类型的 List。因此,您无法确定它的参数类型为 MyType,因此无法实现此行为。

That being said, there are alternative ways of doing this. The most obvious seems to be to listen for bean creation and then seeing if they are of MyType (or subclasses) and then keeping a reference.

话虽如此,还有其他方法可以做到这一点。最明显的似乎是监听 bean 的创建,然后查看它们是否属于 MyType(或子类),然后保留一个引用。

There is probably a few ways to do this. One is creating a bean post-processor. This way you'll get notified of every bean that's created.

可能有几种方法可以做到这一点。一个是创建一个 bean post-processor。通过这种方式,您将收到有关创建的每个 bean 的通知。