Spring: how to create an instance of Spring bean that accepts a runtime parameter?

I have a singleton Spring bean that creates a couple of tasks ( java.util.concurrent.Callable 's) at runtime for parallel work. Right now, Callable defined as inner classes in a singleton bean, and singleton beans create them simply by creating them using new Task(in) , where in is a parameter known only at runtime.

Now I want to extract the inner class Task to a regular top-level class, because I want to make the Task call() method transactional, so I need it to be a Spring bean.

I think I need to give my singleton some kind of factory from Task s, but the tasks should be a prototype of Spring beans that take a run-time value as a constructor parameter. How can i do this?

+7
source share
3 answers

Spring bean factory, and the new ones are mutually exclusive. You cannot call new and expect this object to be under Spring control.

My suggestion is to introduce these Tasks into Singleton. Make them Spring beans, too.

You must admit that the Task itself will not be a transaction, but its dependencies may be. Add them to Tasks and Spring manage your transactions.

+2
source

Another approach might be to use Spring @Configurable annotation with weave with load, so you can use new (instead of bean factory) to create a wired Callable at runtime:

 @Configurable public class WiredTask implements Callable<Result> { @Autowired private TaskExecutor executor; public WiredTask(String in) { this.in = in; } public Result call() { return executor.run(in); } } @Bean @Scope("prototype") public class TaskExecutor() { @Transactional public Result run(String in) { ... } } // Example of how you might then use it in your singleton... ExecutorService pool = Executors.newFixedThreadPool(3); WiredTask task = new WiredTask("payload"); Future<Result> result = pool.submit(task); 

See this article for more details. Please note: you cannot use @Configurable and @Transactional in the same bean , hence the need for two classes. For this reason, this may not be the ideal solution if you have many different Callable implementations (since for each of them you will need 2 classes).

+4
source

Your singleton bean can implement BeanFactoryAware and look for beans from the containing spring factory.

 import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; public class MyBeanFactory implements BeanFactoryAware { private BeanFactory beanFactory; public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } public Task createTask(Task in) { return beanFactory.getBean("task",in); } } /////////////// import java.util.concurrent.Callable; import org.springframework.beans.factory.annotation.Configurable; import org.springframework.context.annotation.Scope; import org.springframework.transaction.annotation.Transactional; @Configurable // unless using xml based config @Scope(value="prototype") // tell bean factory to create new instance each time public class Task implements Callable<Object> { private Object in; public Task(Object in) { super(); this.in = in; } @Transactional public Object call() throws Exception { //do real work return in; } } /// 
+3
source

All Articles