[英]How to create a list filled with instances of a prototype bean using annotations?
从这个问题开始: 如何在Spring中定义一个List bean? 我知道我可以定义一个List<Foo> fooList
该List<Foo> fooList
充满Foo
bean实例,但使用XML配置。 这是一个例子:
public interface Foo {
//methods here...
void fooMethod();
}
@Service("foo")
@Scope("prototype")
public class FooImpl implements Foo {
//fields and methods...
@Override
public void fooMethod() {
//...
}
}
@Service("fooCache")
@Scope
public class FooCacheImpl implements Foo {
//fields and methods...
@Override
public void fooMethod() {
//retrieves data from some cache
//...
}
}
@Service("fooWS")
@Scope("prototype")
public class FooWSImpl implements Foo {
//fields and methods...
@Override
public void fooMethod() {
//retrieves data from web service
//...
}
}
我可以通过XML配置客户端:
<bean id="fooClient" class="some.package.FooClient">
<property name="fooList">
<list>
<bean ... /> <!-- This may be fooImpl -->
<bean ... /> <!-- This may be fooCacheImpl -->
<bean ... /> <!-- This may be fooWSImpl -->
<!-- I can have more beans here -->
</list>
</property>
</bean>
我想知道这是否只能通过注释完成,而无需通过XML定义bean。 像这样:
@Component
@Scope("prototype")
public class FooClient {
//which annotation(s) to use here to fill this list with FooImpl instances?
//I understand that if I have two implementations of Foo I may use a @Qualifier
//or use another list to note the different implementations.
private List<Foo> fooList;
public void bar() {
for (Foo foo : fooList) {
foo.fooMethod();
}
}
}
我认为最好是不涉及注入ApplicationContext
或BeanFactory
的解决方案,这样FooClient
不会与Spring类紧密耦合。 另外,就我而言,我不能使用任何Java EE类(如javax.inject.Provider
,如本博文所述: Spring 2.5.x + 3.0.x:从code创建原型实例 。
怎样使用Factory Bean?
我知道您提到过,您不希望与spring过于耦合-对于工厂bean,包含列表的bean并不是那么耦合-只是工厂。
就像是
@Component("fooList")
class ListFactory<List<Foo>> implements FactoryBean, ApplicationContextAware {
ApplicationContext context;
public List<Foo>> getObject() {
List<Foo> list = new ArrayList();
list.add(context.getBean("foo");
list.add(context.getBean("foo");
return list;
}
public void setApplicationContext(ApplicationContext context) {
this.context = context;
}
public boolean isSingleton() {
return false;
}
}
@Component
@Scope("prototype")
class FooClient {
@Inject
@Named("footList")
private List<Foo> fooList;
public void bar() {
for (Foo foo : fooList) {
foo.fooMethod();
}
}
}
自己还没有尝试过,或者遇到了我需要它的情况,因此我不确定它是否可以工作。
如果您直接在代码中进行操作,那么我认为使用PostConstruct
批注将是一种方法:
@Component
@Scope("prototype")
public class FooClient {
....
@PostConstruct
public void init() throws Exception {
fooList = new ArrayList<Foo>();
fooList.add(new FooImpl());
}
我认为使用这种方法会更加灵活,因为我认为只有在FooImpl
对象本身需要其他配置的情况下,您才会为注释所FooImpl
。
那是prototype
范围的限制(或功能)。 医生说这个
与其他作用域相反,Spring不管理原型bean的完整生命周期:容器实例化,配置或组装原型对象,然后将其交给客户端,而没有该原型实例的进一步记录。
因此,在Spring将其交给您之后,它不会保留对其的任何引用,因此无法将其中的任何一个自动fooList
到您的fooList
。 如果您确实添加了@Autowired
@Autowired
private List<Foo> fooList;
它将只创建一个新的FooImpl
对象并将其自动装配为List
的单个元素。
如果您要保留所有创建的Foo
实例的引用,则您很有可能必须自己做。
您可以这样使用方法注入:
public class PrototypeClient {
protected abstract PrototypeBean createPrototype();
private List<PrototypeBean> createPrototypeList() {
int listSize = calculateListSize();
List<Prototype> result = new ArrayList<Prototype(listSize);
for (int i = 0; i < listSize; i++) {
result.add(createPrototype());
}
return result;
}
private int calculateListSize() {
// do your stuff here
}
// ...
}
并具有一个Spring配置为:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="prototypeBean"
class="fully.qualified.class.name.of.Prototype"
scope="prototype" />
<bean id="prototyeClient"
class="fully.qualified.class.name.of.PrototypeClient">
<lookup-method name="createPrototype" bean="prototypeBean"/>
</bean>
</beans>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.