Reputation: 42441
Need some help in spring here. In our project we use XML and annotation configurations (Spring 4.1) Recently I've faced the following task:
I have a list of beans of scope prototype, all of them implement the same interface.
In addition I have one singleton bean that has execute
method. Inside the method the bean should access the list of those prototype beans.
Every time the 'execute' method gets executed I would like to get the access to the different instances of those prototype beans).
In singleton I don't have the whole list of beans known in advance, so I just @Autowire
the whole collection so that every bean implementation known in the application context will be loaded.
interface SomeInterface {
}
class PrototypeBean1 implements SomeInterface {
...
}
class PrototypeBean2 implements SomeInterface {
...
}
class MySingletonBean {
@Autowire (????)
List<SomeInterface> allPrototypeBeansLoadedIntoTheApplicationContext;
public void execute() {
// this one is called many times,
// so I would like to get different lists of
//"allPrototypeBeansLoadedIntoTheApplicationContext"
// with different actuals bean upon every invocation
// how do I achieve this???
}
}
So my question is: What is the most clean way to achieve this? Ideally I would like to get a solution totally decoupled from spring interfaces (like injecting ApplicationContext/BeanFactory stuff) I don't mind to use Aop here (performance is not that critical), but I can't really wrap my head around a clean spring solution. So any help will be appreciated.
Thanks in advance
Upvotes: 1
Views: 1376
Reputation: 51
I have been trying to achieve similar goal with Spring and after reading Spring docs using either ServiceLocatorFactoryBean or method injection (with @Lookup) came up and looked promising. However after tried both approach results turned out to be frustrating. Neither way supports returning beans in List. And I got this exception:
No qualifying bean of type 'java.util.List' available
Apparently Spring treated the return type as a regular Object.
So eventually my solution became creating a new object to wrap the list as return type.
@Component
@Scope("prototype")
public class ProcessorList
{
private List<Processor> processors;
public ProcessorList(List<Processor> processors)
{
this.processors = processors;
}
public List<Processor> getProcessors()
{
return processors;
}
public void setProcessors(List<ChangeSetProcessor> processors)
{
this.processors = processors;
}
}
then create a Factory class for the List Object:
@Component
public interface ProcessorFactory
{
ProcessorList getProcessorList();
}
Then use ServiceLocatorFactoryBean to register the factory:
@Configuration
public class MyConfiguration{
@Bean
public FactoryBean serviceLocatorFactoryBean()
{
ServiceLocatorFactoryBean factoryBean = new ServiceLocatorFactoryBean();
factoryBean.setServiceLocatorInterface(ProcessorFactory.class);
return factoryBean;
}
}
Finally implement the interface and make sure mark them all with @Scope("prototype")
Now you'll get new instance each time you use the factory method!
It's similar to use method injection if you prefer.
Upvotes: 1