Spring 按类型列出 Bean

发布于 2024-08-05 16:52:50 字数 203 浏览 13 评论 0原文

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

setMyProp(List<MyType> list)

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

谢谢, 杰夫

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:

setMyProp(List<MyType> list)

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

Thanks,
Jeff

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

兲鉂ぱ嘚淚 2024-08-12 16:52:50

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

也可以提供所有
特定类型的豆子
ApplicationContext 通过添加
字段或方法的注释
需要该类型的数组。

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

<?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>

以及此单元测试:

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 {}

}

因此,正式而言,您应该自动装配 TypeA[],而不是 List,而是该列表效果很好。

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.

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.

余厌 2024-08-12 16:52:50

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

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.XmlBeanFactory and ask it "getBeansOfType( MyType.class )". This gives you all beans of type (and subtype) of MyType.

仲春光 2024-08-12 16:52:50

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

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

这会将所有实现 SuperType 作为 List 的顶级 Spring beans 注入到客户端 bean 中。

If you can use @Autowired inside 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 Hera to achieve this. Esentially configuration of a scenario described by you looks like this:

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

This will inject all top-level Spring beans implementing SuperType as List into the client bean.

抠脚大汉 2024-08-12 16:52:50

简短的回答:不。

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

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

可能有几种方法可以做到这一点。一是创建一个bean后处理器。这样您就会收到创建的每个 bean 的通知。

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.

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.

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.

七禾 2024-08-12 16:52:50

由于遗留代码和缺少@Autowired,我解决它的方式如下:

MyBean implements ApplicationContextAware{

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

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

MyBean implements ApplicationContextAware{

  @Override
  public void setApplicationContext(ApplicationContext ctx) throws BeansException {
    final Map<String, HttpRequestHandlerTemplate> beansOfType = ctx.getBeansOfType(RequiredBean.class);
    ...
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文