如何使用注释创建一个填充原型bean实例的列表?

时间:2013-10-14 20:01:17

标签: java spring

从这个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();
        }
    }
}

我认为这样做更好的解决方案不涉及注入ApplicationContextBeanFactory,因此FooClient与Spring类没有紧密耦合。另外,对于我的情况,我不能使用javax.inject.Provider之类的任何Java EE类,如本博文中所示:Spring 2.5.x+3.0.x: Create prototype instances from code

4 个答案:

答案 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>