Java spring:如何在使用@Autowired 和 context:component-scan 自动连接原型 bean 时使用非默认构造函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25232034/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
spring: how to use non-default constructor when auto-wiring a prototype bean using @Autowired and context:component-scan?
提问by JBT
Suppose you have a prototype bean class as below:
假设您有一个原型 bean 类,如下所示:
@Component
@Scope("prototype")
public class Foobar {
private String foo;
public Foobar( String foo ) {
this.foo = foo;
}
}
So, is it possible to use @Autowired
to wire such a bean in another class, which should use the non-default constructor Foobar(String foo)
to instantiate the bean?
那么,是否可以将@Autowired
这样的 bean 连接到另一个类中,该类应该使用非默认构造函数Foobar(String foo)
来实例化 bean?
update
In the example above, the constructor parameter, String foo
, is not available from application context but rather dynamic. So, having the constructor annotated with @Autowired
and then specifying foo
somewhere in the context doesn't seem an ideal solution here.
update
在上面的示例中,构造函数参数String foo
不能从应用程序上下文中获得,而是动态的。因此,对构造函数进行注释@Autowired
然后foo
在上下文中的某处指定在这里似乎不是一个理想的解决方案。
回答by Francisco Spaeth
Here are 3 ways to do it, just peek the best one for your case:
这里有 3 种方法,只需查看最适合您的情况的方法:
Using @Autowired constructors
使用@Autowired 构造函数
Better when: you have all you need to build your prototype bean in the context (even for properties such as @Value("${prop}")
)
更好的时候:您拥有在上下文中构建原型 bean 所需的一切(即使对于诸如 之类的属性@Value("${prop}")
)
If you want an automatic way to do it, you will need to have everything that is needed to instantiate the bean in the context too (even for a prototype bean). In case you have everything needed in your context you could simply annotate the constructor as @Autowired
and Spring will do the rest for your.
如果您想要一种自动的方式来做到这一点,您也需要拥有在上下文中实例化 bean 所需的一切(即使对于原型 bean)。如果您在上下文中拥有所需的一切,您可以简单地注释构造函数@Autowired
,Spring 将为您完成其余的工作。
@Component
@Scope("prototype")
public class FooBar {
private Baz baz;
@Autowired
public FooBar(Baz baz) {
this.baz = baz;
}
}
Using FactoryBeans
使用 FactoryBeans
Better when: if you are using an XML based context, you will prefer this way.
更好的情况:如果您使用基于 XML 的上下文,您会更喜欢这种方式。
Another possibility, if you need a personalized way to do it, would be using FactoryBean
s. From documentation:
另一种可能性,如果您需要一种个性化的方式来做到这一点,将使用FactoryBean
s。从文档:
Interface to be implemented by objects used within a BeanFactory which are themselves factories. If a bean implements this interface, it is used as a factory for an object to expose, not directly as a bean instance that will be exposed itself.
由 BeanFactory 中使用的对象实现的接口,这些对象本身就是工厂。如果一个 bean 实现了这个接口,它就被用作一个对象暴露的工厂,而不是直接作为一个将暴露自己的 bean 实例。
The FactoryBean
is used by Spring just to build the object you requested (being it a prototype or singleton).
该FactoryBean
所使用的春天刚刚建立你请求的对象(即其原型或单)。
For your case you could have an implementation like:
对于您的情况,您可以有一个实现,如:
@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;
}
}
And you could simple @Autowired
FooBar
on other instances of your context.
您可以简化@Autowired
FooBar
上下文的其他实例。
Using @Configuration
使用 @Configuration
Better when: if you already have your context configured using annotations you will definitely prefer this way.
更好的时候:如果您已经使用注释配置了您的上下文,您肯定会更喜欢这种方式。
A third way to do it, and this is my favorite, would be using your @Configuration
class. From documentation:
第三种方法,这是我最喜欢的,就是使用你的@Configuration
类。从文档:
public @interface Configuration
: Indicates that a class declares one or more @Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime, for example:
public @interface Configuration
:表示一个类声明了一个或多个@Bean方法,并且可能会被Spring容器处理,在运行时为这些bean生成bean定义和服务请求,例如:
Within that class your could have a method like:
在该类中,您可以使用如下方法:
@Configuration
public class MyConfig {
@Bean
@Scope("prototype")
public FooBar fooBar(Baz myContextProvidedObject) {
return new FooBar(myContextProvidedObject, "my parameter");
}
}
回答by LeTex
You need to annotate your constructor with @Autowired and for the parameter that has to be passed to the constructor when your bean get instantiated, you have to use a non-primitive type parameter:
您需要使用 @Autowired 注释您的构造函数,并且对于实例化 bean 时必须传递给构造函数的参数,您必须使用非原始类型参数:
For example:
例如:
@Component
@Scope("prototype")
public class FooBar {
private DataSource data;
@Autowired
public FooBar(DataSource data) {
this.bdata = data;
}
}
and then annotate your DataSource with:
然后使用以下内容注释您的数据源:
@Component("dataSupplier")
public class DataSource {
public int getData() {}
}
回答by Fahim Farook
Since component scanning has been enabled, spring will try to automatically discover and register another Foobar bean. However this will fail because spring can't create an object using the defined constructor as you have not auto-wired the constructor / parameters in the constructor. As the second step spring will try to create a Foobar with no-args constructor. Therefore you need to have auto-wired the constructor which you defined in the spring-config file in order to get rid of this error. Please refer to this articlefor more information on this topic.
由于启用了组件扫描,spring 将尝试自动发现并注册另一个 Foobar bean。但是这会失败,因为 spring 无法使用定义的构造函数创建对象,因为您没有在构造函数中自动连接构造函数/参数。作为第二步,spring 将尝试创建一个带有 no-args 构造函数的 Foobar。因此,您需要自动连接您在 spring-config 文件中定义的构造函数,以消除此错误。有关此主题的更多信息,请参阅本文。