I have an interface/implementation like so:
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
}
}
The FooA
bean is simple, like this:
@Component
public class FooA {
//stuff
}
And the message class:
public class Message {
private Class clazz;
}
I am pulling messages off a queue. I need to provide a concrete Processor to handle the different types of messages appropriately. Here's the message receiver:
public class MessageReceiver {
public void handleMessage(Message m) {
Processor processor = //get concrete implementation from Message clazz
processor.processMessage(m);
}
}
How exactly can I use the class name/object to define a concrete implementation of Processor
?
My first thought was to develop some sort of a factory that takes in a class and provides the concrete implementation. Something like this:
@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;
}
}
}
Or to use the application context like this:
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getBean(clazz);
Is this the best way to go about this problem? Is there a better practice?
You can inject ApplicationContext
into your factory and get beans from there:
@Component
public class Factory {
@Autowired ApplicationContext applicationContext;
public Object getBean(String beanName) {
return applicationContext.getBean(beanName);
}
}
Or you can put your processors into map
and get them from it:
@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);
}
}
I recommend to not rely on class when working with spring context but use beanNames instead.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.