从这个Q / A:How to define a List bean in Spring?我知道我可以定义一个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类没有紧密耦合。另外,对于我的情况,我不能使用javax.inject.Provider
之类的任何Java EE类,如本博文中所示:Spring 2.5.x+3.0.x: Create prototype instances from code。
答案 0 :(得分:1)
使用Factory 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();
}
}
}
我自己没有尝试过,或者有我需要它的场景所以我不确定它是否会起作用。
答案 1 :(得分:0)
如果您直接在代码中执行此操作,那么我认为使用PostConstruct
注释将是最佳选择:
@Component
@Scope("prototype")
public class FooClient {
....
@PostConstruct
public void init() throws Exception {
fooList = new ArrayList<Foo>();
fooList.add(new FooImpl());
}
我认为使用这种方法会更灵活,因为我认为只有当FooImpl
对象本身需要额外配置时才会使用注释。
答案 2 :(得分:0)
这是prototype
范围的限制(或特征)。 The docs say this
与其他范围相比,Spring不管理完整的范围 原型bean的生命周期:容器实例化,配置, 并以其他方式组装原型对象,并将其交给 客户端,没有该原型实例的进一步记录。
所以在Spring交给你之后,它没有任何对它的引用,因此不能将它们中的任何一个自动装入你的fooList
。如果您确实添加了@Autowired
@Autowired
private List<Foo> fooList;
它只会创建一个新的FooImpl
对象,并将其作为List
中的单个元素自动装配。
如果您要保留对所有Foo
个实例的引用,那么您很可能必须自己完成。
答案 3 :(得分:0)
您可以使用方法注入:
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>