具有运行时构造函数参数的Spring bean

时间:2016-01-31 00:09:14

标签: java spring spring-bean

我想在 Spring Java配置中创建一个Spring bean,并在运行时传递一些构造函数参数。我创建了以下Java配置,其中有一个bean fixedLengthReport ,它需要构造函数中的一些参数。

@Configuration
public class AppConfig {

    @Autowrire
    Dao dao;

    @Bean
    @Scope(value = "prototype")
    **//SourceSystem can change at runtime**
    public FixedLengthReport fixedLengthReport(String sourceSystem) {
         return new TdctFixedLengthReport(sourceSystem, dao);
    }
}

但是我收到的错误是 sourceSystem 无法连接,因为找不到bean。如何使用运行时构造函数参数创建bean?

我使用的是Spring 4.2

3 个答案:

答案 0 :(得分:36)

您可以将原型bean与BeanFactory一起使用。

@Configuration
public class AppConfig {

   @Autowired
   Dao dao;

   @Bean
   @Scope(value = "prototype")
   public FixedLengthReport fixedLengthReport(String sourceSystem) {
       return new TdctFixedLengthReport(sourceSystem, dao);
   }
}

@Scope(value = "prototype")意味着Spring不会在启动时实例化bean,但会在以后按需执行。现在,要自定义原型bean的实例,您必须执行以下操作。

@Controller
public class ExampleController{

   @Autowired
   private BeanFactory beanFactory;

   @RequestMapping("/")
   public String exampleMethod(){
      TdctFixedLengthReport report = 
         beanFactory.getBean(TdctFixedLengthReport.class, "sourceSystem");
   }
}

注意,因为你的bean在启动时无法实例化,你不能直接自动装配你的bean;否则Spring会尝试实例化bean本身。此用法将导致错误。

@Controller
public class ExampleController{

   //next declaration will cause ERROR
   @Autowired
   private TdctFixedLengthReport report;

}

答案 1 :(得分:2)

你的代码看起来很好,用参数使用BeanFactory#getBean(String name,Object ... args)方法来获取原型。

看看Spring Java Config: how do you create a prototype-scoped @Bean with runtime arguments? BeanFactory#getBean(String name,Object ... args)就是你要找的东西。

我想你的IDEA(在我的情况下是IntelliJ IDEA版本15)会给你错误,而不是运行时/编译时错误。

在IntelliJ中,您可以更改弹簧检查的设置。

  • 转到档案 - >设置。
  • 在搜索框中键入检查。
  • 转到Spring Core-> Code->自动加入Bean类。
  • 从“错误”更改为“弱警告”

答案 2 :(得分:0)

这可以通过Spring 4.3中引入的Spring ObjectProvider<>类来实现。有关更多详细信息,请参见Spring的documentation

要点是为要提供的对象定义bean工厂方法,将ObjectProvider<>注入到使用者中,并创建要提供的对象的新实例。

public class Pair
{
    private String left;
    private String right;

    public Pair(String left, String right)
    {
        this.left = left;
        this.right = right;
    }

    public String getLeft()
    {
        return left;
    }

    public String getRight()
    {
        return right;
    }
}

@Configuration
public class MyConfig
{
    @Bean
    @Scope(BeanDefinition.SCOPE_PROTOTYPE)
    public Pair pair(String left, String right)
    {
        return new Pair(left, right);
    }
}

@Component
public class MyConsumer
{
    private ObjectProvider<Pair> pairProvider;

    @Autowired
    public MyConsumer(ObjectProvider<Pair> pairProvider)
    {
        this.pairProvider = pairProvider;
    }

    public void doSomethingWithPairs()
    {
        Pair pairOne = pairProvider.getObject("a", "b");
        Pair pairTwo = pairProvider.getObject("z", "x");
    }
}

注意:您实际上并未实现ObjectProvider<>接口; Spring会自动为您做到这一点。您只需要定义bean工厂方法。