spring:如何在使用@Autowired和context:component-scan自动连接原型bean时使用非默认构造函数?

时间:2014-08-10 19:07:26

标签: java spring

假设您有一个原型bean类,如下所示:

@Component
@Scope("prototype")
public class Foobar {
    private String foo;
    public Foobar( String foo ) {
        this.foo = foo;
    }
}

那么,是否可以使用@Autowired将这样的bean连接到另一个类中,该类应该使用非默认构造函数Foobar(String foo)来实例化bean?

更新
在上面的示例中,构造函数参数String foo在应用程序上下文中不可用,而是动态的。因此,使用@Autowired注释构造函数,然后在上下文中的某处指定foo似乎不是一个理想的解决方案。

3 个答案:

答案 0 :(得分:18)

以下是3种方法,只需查看最适合您情况的方法:

使用@Autowired构造函数

更好:您拥有在上下文中构建原型bean所需的一切(即使是@Value("${prop}")等属性)

如果你想要一种自动方式,你需要拥有在上下文中实例化bean所需的一切(即使对于原型bean)。如果您在上下文中拥有所需的所有内容,您只需将构造函数注释为@Autowired,Spring将为您完成剩下的工作。

@Component
@Scope("prototype")
public class FooBar {

    private Baz baz;

    @Autowired
    public FooBar(Baz baz) {
        this.baz = baz;
    }

}

使用FactoryBeans

更好:如果您使用的是基于XML的上下文,您会更喜欢这种方式。

如果您需要个性化的方式,另一种可能性是使用FactoryBean。来自documentation

  

由BeanFactory中使用的对象实现的接口,这些对象本身就是工厂。如果bean实现了这个接口,它将被用作公开的对象的工厂,而不是直接作为将自己公开的bean实例。

Spring使用FactoryBean来构建您请求的对象(原型或单例)。

对于您的情况,您可以使用以下实现:

@Component
public class FooBarFactory implements FactoryBean<FooBar> {

    @Autowired
    private Baz myContextProvidedObject;

    @Override
    public FooBar getObject() throws Exception {
        return new FooBar(myContextProvidedObject, "my parameter");
    }

    @Override
    public Class<?> getObjectType() {
        return FooBar.class;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }

}

您可以在上下文的其他实例上简单@Autowired FooBar

使用@Configuration

更好:如果您已经使用注释配置了上下文,那么您肯定会更喜欢这种方式。

第三种方式,这是我的最爱,将使用你的@Configuration课程。来自documentation

  

public @interface Configuration:表示一个类声明了一个或多个@Bean方法,可能是   由Spring容器处理以生成bean定义和   在运行时为这些bean提供服务请求,例如:

在该课程中,您可以使用以下方法:

@Configuration
public class MyConfig {

    @Bean
    @Scope("prototype")
    public FooBar fooBar(Baz myContextProvidedObject) {
        return new FooBar(myContextProvidedObject, "my parameter");
    }

}

答案 1 :(得分:3)

您需要使用@Autowired注释构造函数 对于在实例化bean时必须传递给构造函数的参数,必须使用非基本类型参​​数:

例如:

@Component
@Scope("prototype")
public class FooBar {

    private DataSource data;

    @Autowired
    public FooBar(DataSource data) {
        this.bdata = data;
    }
}

然后使用以下命令注释您的DataSource:

@Component("dataSupplier")
public class DataSource {

    public int getData() {}
}

答案 2 :(得分:1)

由于已启用组件扫描,spring将尝试自动发现并注册另一个Foobar bean。但是这会失败,因为spring无法使用定义的构造函数创建对象,因为您没有在构造函数中自动连接构造函数/参数。作为第二步,spring将尝试使用no-args构造函数创建Foobar。因此,您需要自动连接在spring-config文件中定义的构造函数,以消除此错误。有关此主题的更多信息,请参阅此article