【问题标题】:Spring Bean Factory Using Class Name使用类名的 Spring Bean Factory
【发布时间】:2017-08-25 00:02:46
【问题描述】:

我有一个这样的接口/实现:

public interface Processor {
    void processMessage(Message m);
}

@Component
public class FooAProcessor implements Processor {
    private FooA fooA;

    public FooAProcessor(FooA fooA) {
        this.fooA = fooA;
    }

    @Override
    public void processMessage(Message m) {
        //do stuff
    }
}

@Component
public class FooBProcessor implements Processor {
    private FooA fooA;

    public FooBProcessor(FooA fooA) {
        this.fooA = fooA;
    }

    @Override
    public void processMessage(Message m) {
        //do stuff
    }
}

FooA bean 很简单,如下所示:

@Component
public class FooA {
    //stuff
}

还有消息类:

public class Message {
    private Class clazz;
}

我正在从队列中提取消息。我需要提供一个具体的处理器来适当地处理不同类型的消息。这是消息接收者:

public class MessageReceiver {
    public void handleMessage(Message m) {
        Processor processor = //get concrete implementation from Message clazz
        processor.processMessage(m);
    }
}

我如何准确地使用类名/对象来定义Processor 的具体实现?

我的第一个想法是开发某种工厂,它接收一个类并提供具体实现。像这样的:

@Component
public class ProcessorFactory {
    private FooAProcessor fooAProcessor;
    private FooBProcessor fooBProcessor;

    public ProcessorFactory(FooAProcessor fooAProcessor, FooBProcessor fooBProcessor) {
        this.fooAProcessor = fooAProcessor;
        this.fooBProcessor = fooBProcessor;
    }

    public Processor getFactory(Class clazz) {
        if(clazz.isAssignableFrom(FooAProcessor.class)) {
            return fooAProcessor;
        }
    }
}

或者像这样使用应用程序上下文:

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getBean(clazz);

这是解决此问题的最佳方法吗?有更好的做法吗?

【问题讨论】:

  • 你可以按类从应用上下文中获取bean。但我怀疑这是否是一个合理的设计。我宁愿在Message中引入某种消息类型标识符,并设置MessageReceiver使用的messageType-vs-Processor查找映射
  • @Richard 你快到了 应用程序上下文本身是一个工厂接口,用于根据类型或名称获取适当的 bean。所以不要再定义一个工厂,而是写一个utiltiy类来根据类型或名称获取bean。

标签: java spring javabeans factory factory-pattern


【解决方案1】:

您可以将ApplicationContext 注入您的工厂并从那里获取bean:

@Component
public class Factory {

    @Autowired ApplicationContext applicationContext;

    public Object getBean(String beanName) {
        return applicationContext.getBean(beanName);
    }
}

或者您可以将您的处理器放入map 并从中获取它们:

@Component
public class ProcessorFactory {

    private final Processor fooAProcessor;
    private final Processor fooBProcessor;
    private final Map<Class<T extends Processor>, Processor> beanMap;

    public ProcessorFactory (Processor fooAProcessor, Processor fooBProcessor) {
        this.fooAProcessor = fooAProcessor;
        this.fooBProcessor = fooBProcessor;
        this.beanMap = new HashMap(2);
    }

    @PostConstruct
    public void init() {
        beanMap.put(FooAProcessor.class, fooAProcessor);
        beanMap.put(FooBProcessor.class, fooBProcessor);
    }

    public Processor getProcessor(Class<T extends Processor> clazz) {
        return beanMap.get(clazz);
    }
}

我建议在使用 spring 上下文时不要依赖类,而是使用 beanNames。

【讨论】:

  • 我更喜欢您的第二个解决方案。我试过这样做,但我认为你不能在接口上做extends。我收到 unexpected bounds 错误。
猜你喜欢
  • 1970-01-01
  • 2013-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多