我有一个单独的Spring bean,它在运行时创建了几个任务(java.util.concurrent.Callable
)来并行完成它的工作。现在,Callable
被定义为单例bean中的内部类,而单例bean仅通过使用new Task(in)
实例化它们来创建它们,其中in
是仅在运行时。
现在我想将内部Task类提取到常规顶级类,因为我想让Task的call()
方法成为事务性的,所以我需要它成为一个Spring bean。
我想我需要为我的单例提供Task
s的某种工厂,但任务必须是原型Spring bean,它将运行时值作为构造函数参数。我怎么能做到这一点?
答案 0 :(得分:4)
另一种方法可能是使用Spring的@Configurable
注释和加载时编织,这样你就可以使用new
(而不是bean工厂)在运行时创建有线Callable:
@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);
有关详细信息,请参阅this article。注意,你不能使用@Configurable and @Transactional in the same bean,因此需要两个类。因此,如果您有许多不同的Callable实现,这可能不是理想的解决方案(因为每个类需要2个类)。
答案 1 :(得分:3)
您的单例bean可以从包含的spring工厂实现BeanFactoryAware和查找bean。
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;
}
}
///
答案 2 :(得分:2)
Spring的bean工厂和新工厂相互排斥。你不能调用new并期望该对象受Spring控制。
我的建议是将这些任务注入Singleton。让它们成为春豆。
您应该认识到Task本身不是事务,但它的依赖关系可以是。将这些注入任务并让Spring管理事务。