繁体   English   中英

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

[英]How to create a list filled with instances of a prototype bean using annotations?

从这个问题开始: 如何在Spring中定义一个List bean? 我知道我可以定义一个List<Foo> fooListList<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类紧密耦合。 另外,就我而言,我不能使用任何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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM