I want to create some spring beans after startup in a factory-ish pattern. For example every so often I have some work to do and I need to create a task bean (which probably has dependents on other singleton spring beans) and execute it.
There may be several pieces of work to execute concurrently so each task bean needs to be independent (prototype).
Is there any common pattern people use to achieve this?
As I see it I need to interact with the container/applicationContext somehow but I don't really want to scatter injections of applicationContext/beanFactory and calls to getBean("...") everywhere.
I thought of something like this (note the "factory" is something I'm imagining, rather than something that exists)
<bean id="myTask" class="MyTask" scope="prototype">
<property name="entityManager" ref=".../>
...
</bean>
<bean id="myTaskExecutor" class="MyTaskExecutor">
<property name="taskFactory">
<xxx:factory bean="myTask"/>
</property>
</bean>
And then code
class MyTaskExecutor
{
private Factory<MyTask> taskFactory;
public void setTaskFactory( Factory<MyTask> taskFactory )
{
this.taskFactory = taskFactory;
}
}
And maybe an annotation version
class MyTaskExecutor
{
@Factory(MyTask.class)
private Factory<MyTask> taskFactory;
}
Maybe there's something like the above already? Or am I missing something fundamental somewhere.
I realise I could have a singleton MyTaskFactory and use that to instantiate using "new" but then I'd have to pass all of it's dependents from the factory which feels wrong.
So I guess to sum up the question is
What is the recommended way of creating prototype spring beans on-demand from within application code?
Appreciate any input.
I think you're over-complicating the problem. All you need to do is write a TaskFactory
class (nothing special about it, no special interfaces or annotations). TaskFactory
would be injected with all the other beans needed, and would have a createTask
method which creates the tasks on demand, and which passes references to the required Spring beans to the new task when it's created. Client code is injected with TaskFactory
, and calls createTask
when required.
Spring itself provides no explicit support for what you're trying to do. The likes of factory-method
XML attributes and FactoryBean
interfaces are only useful for one-off creation of a bean within its scope, and if you want to create them on demand, that means scope="prototype"
, and that means using getBean()
.
edit: It's probably worth pointing out that prototype-scoped beans are really not what Spring is designed for. Yes, it supports them, but using them is not a very edifying experience. If you really want to go down this road, then it's worth taking a look at @Configurable
. It's very powerful, but not always suitable, because of runtime classloader constraints.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With