1

来自这个 Q/A:如何在 Spring 中定义 List bean?我知道我可以定义一个List<Foo> fooList填充Foobean 实例但使用 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也不与 Spring 类紧密耦合。此外,就我而言,我不能使用任何 Java EE 类,如本博文所示:Spring 2.5.x+3.0.x: Create prototype instances from codeBeanFactoryFooClientjavax.inject.Provider

4

4 回答 4

1

使用工厂 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();
        }
    }
}

我自己没有尝试过,或者有我需要它的场景,所以我不确定它是否会起作用。

于 2013-10-14T20:37:32.193 回答
0

如果您直接在代码中执行此操作,那么我认为使用PostConstruct注释将是可行的方法:

@Component
@Scope("prototype")
public class FooClient {

....

    @PostConstruct
    public void init() throws Exception {
        fooList = new ArrayList<Foo>();
        fooList.add(new FooImpl());
    }

我认为使用这种方法会更加灵活,因为我认为只有当FooImpl对象本身需要额外配置时,您才会遇到注释。

于 2013-10-14T20:20:03.147 回答
0

这是范围的限制(或功能)prototype文档这样说

与其他作用域相比,Spring 不管理原型 bean 的完整生命周期:容器实例化、配置和以其他方式组装原型对象,并将其交给客户端,而无需进一步记录该原型实例。

因此,在 Spring 将其交给您之后,它不会保留对它的任何引用,因此无法将它们中的任何一个自动装配到您的fooList. 如果你确实添加了@Autowired

@Autowired 
private List<Foo> fooList;

它只会创建一个新FooImpl对象并将其作为List.

如果您试图保留所有Foo创建的实例的引用,您很可能必须自己做。

于 2013-10-14T20:27:07.120 回答
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>                                 
于 2013-10-18T09:36:35.870 回答