【问题标题】:Spring: how to instantiate a Spring bean that takes a runtime parameter?Spring:如何实例化一个带有运行时参数的 Spring bean?
【发布时间】:2012-02-24 11:10:02
【问题描述】:

我有一个单例 Spring bean,它在运行时创建几个任务 (java.util.concurrent.Callable's) 以并行完成其工作。现在,Callable 被定义为单例 bean 中的内部类,单例 bean 只需使用 new Task(in) 实例化它们即可创建它们,其中 in 是仅在运行时才知道的参数。

现在我想将内部的 Task 类提取到一个常规的顶级类,因为我想让 Task 的 call() 方法具有事务性,所以我需要它是一个 Spring bean。

我想我需要给我的单例一些Tasks 的工厂,但任务必须是原型 Spring bean,它以运行时值作为构造函数参数。我怎样才能做到这一点?

【问题讨论】:

  • @BorisTreukhov:这不是关于测试多线程应用程序的问题,而是关于 Spring 的问题。事实上,我将从我的问题中删除原因 #2,因为它分散了真正问题的注意力。
  • @Bossie 好的,我删除了我的评论,顺便说一句,我认为最简单的方法是创建单独的服务 bean,将它们的方法装饰为事务性,将它们注入你的单例并将“in”参数传递给服务方法。

标签: java spring parameters prototype


【解决方案1】:

Spring 的 bean factory 和 new 是互斥的。您不能调用 new 并期望该对象在 Spring 的控制之下。

我的建议是将这些任务注入到单例中。也让它们成为 Spring bean。

您应该认识到任务本身不会是事务,但它的依赖项可以。将它们注入到任务中,让 Spring 管理事务。

【讨论】:

  • KISS +1。没有理由让事情变得更难,只需创建事务服务并将其注入任务。
  • "Spring 的 bean factory 和 new 是互斥的。"这对大多数人来说似乎很明显,但对于一个春季新手来说,这对我来说非常重要。它帮助我了解了 spring 的实际作用。
  • 但是如果我不知道任务数怎么办? IE。有人提交了一个带有数字的工作,比如 10,我实例化了 10 个任务?请问在这种情况下如何将Tasks注入Singleton?
  • 您应该创建一个执行器池并让他们处理您的任务。忘记 Singleton 并学习 Spring。
【解决方案2】:

另一种方法可能是将 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 个类)。

【讨论】:

    【解决方案3】:

    您的单例 bean 可以实现 BeanFactoryAware 并从包含的 spring 工厂查找 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;
        }   
    }
    ///
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-30
      • 2017-04-23
      • 2016-06-08
      • 1970-01-01
      • 2017-08-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多