java 获取所有在 Spring 中实现通用接口的 bean

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3228376/
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-30 00:54:02  来源:igfitidea点击:

Get all beans implementing a generic interface in Spring

javaspring

提问by Ola Herrdahl

How do I get a reference of all beans implementing a specific generic interface (e.g. Filter<TestEvent>) in Spring?

如何获得<TestEvent在 Spring 中实现特定通用接口(例如 Filter >)的所有 bean 的引用?

This is what I want to achieve with a minimum number of lines:

这就是我想用最少的行数实现的目标:

public interface Filter<T extends Event> {

    boolean approve(T event);

}


public class TestEventFilter implements Filter<TestEvent> {

    public boolean approve(TestEvent event){
        return false;
    }

}

public class EventHandler{
    private ApplicationContext context;

    public void Eventhandler(DomainEvent event) {
        // I want to do something like following, but this is not valid code
        Map<String, Filter> filters = context.getBeansOfType(Filter<event.getClass()>.class);
        for(Filter filter: filters.values()){
            if (!filter.approve(event)) {
                return;  // abort if a filter does not approve the event
            }
        }
        //...
    }

}

My current implementation uses reflection to determine if filter.approve does accept the event before calling it. E.g.

我当前的实现使用反射来确定 filter.approve 在调用它之前是否确实接受了该事件。例如

        Map<String, Filter> filters = context.getBeansOfType(Filter.class);
        for(Filter filter: filters.values()){
            if (doesFilterAcceptEventAsArgument(filter, event)) {
                if (!filter.approve(event)) {
                    return;  // abort if a filter does not approve the event
                }
            }
        }

Where the doesFilterAcceptEventAsArgument does all the ugly work that I would like would like to get away from. Any suggestions?

dosFilterAcceptEventAsArgument 在哪里完成我想要摆脱的所有丑陋的工作。有什么建议?

采纳答案by Andrzej Doyle

If your question is "does Spring have a nicer way to do this", then the answer is "no". Hence, your method looks like the ubiquitous way to achieve this (get all beans of the raw class, then use reflection to look up the generic bound and compare it with the target's class).

如果您的问题是“Spring 是否有更好的方法来做到这一点”,那么答案是否定的。因此,您的方法看起来像是实现这一点的普遍方法(获取原始类的所有 bean,然后使用反射查找泛型边界并将其与目标类进行比较)。

In general, using generic information at runtime is tricky if possible at all. In this case you can get the generic bounds, but you're not really getting much benefit from the generic definition itself, other than using it as a form of annotation to check manually.

一般来说,如果可能的话,在运行时使用通用信息是很棘手的。在这种情况下,您可以获得泛型边界,但除了将其用作手动检查的注释形式之外,您并没有真正从泛型定义本身中获得多少好处。

In any case, you will have to perform somekind of check on the returned object, so your original code block isn't going to work; the only variation is in the implementation of doesFilterAcceptEventAsArgument. The classic OO way, would be to add an abstract superclass with two methods as follows (and add the latter to the Filter interface):

在任何情况下,您都必须对返回的对象执行某种检查,因此您的原始代码块将无法工作;唯一的变化是在doesFilterAcceptEventAsArgument. 经典的 OO 方法是添加一个具有以下两个方法的抽象超类(并将后者添加到 Filter 接口):

protected abstract Class<E> getEventClass();

public boolean acceptsEvent(Object event) // or an appropriate class for event
{
    return getEventClass().isAssignableFrom(event.getClass());
}

This is kind of a pain because you'll have to implement the trivial getEventClass()methods in every implementation to return the appropriate class literal, but it's a known limitation of generics. Within the bounds of the language, this is likely the cleanest approach.

这有点痛苦,因为您必须getEventClass()在每个实现中实现琐碎的方法才能返回适当的类文字,但这是泛型的已知限制。在语言范围内,这可能是最干净的方法。

But yours is fine for what it's worth.

但你的物有所值。

回答by Ola Herrdahl

Just for reference, the simplest solution I could construct was this:

仅供参考,我可以构建的最简单的解决方案是:

    Map<String, Filter> filters = context.getBeansOfType(Filter.class);
    for(Filter filter: filters.values()){
        try {
            if (!filter.approve(event)) {
                return;  // abort if a filter does not approve the event.
            }
        } catch (ClassCastException ignored){ }
    }

And it worked quite well for prototyping.

它非常适合原型设计。