简体   繁体   English

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

[英]Get all beans implementing a generic interface in Spring

How do I get a reference of all beans implementing a specific generic interface (eg Filter <TestEvent >) in Spring? 如何在Spring中获得实现特定通用接口(例如Filter <TestEvent >)的所有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. 我当前的实现使用反射来确定filter.approve在调用之前是否接受了该事件。 Eg 例如

        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. 在什么地方,doFilterAcceptEventAsArgument完成了我想要摆脱的所有丑陋的工作。 Any suggestions? 有什么建议?

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. 它在原型设计方面表现得非常好。

If your question is "does Spring have a nicer way to do this", then the answer is "no". 如果你的问题是“Spring是否有更好的方法来做到这一点”,那么答案就是“不”。 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). 因此,您的方法看起来像无处不在的方法来实现这一点(获取原始类的所有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 some kind 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 . 唯一的变化是在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): 经典的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. 这是一种痛苦,因为你必须在每个实现中实现简单的getEventClass()方法来返回相应的类文字,但这是已知的泛型限制。 Within the bounds of the language, this is likely the cleanest approach. 在语言的范围内,这可能是最干净的方法。

But yours is fine for what it's worth. 但你的价值不错。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM