2013-10-14 2 views
0

Из этого Q/A: How to define a List bean in Spring? Я знаю, что могу определить List<Foo> fooList, заполненный экземплярами bean-ов Foo, но используя конфигурацию 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. Что-то вроде этого:

@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: Create prototype instances from code.

+0

вы хотите создать многие из той же компоненты в списке? –

+0

вы можете создать много аннотированных инъекций сеттера, каждый из которых будет принимать компонент типа, и они добавят компонент в инкапсулированный список. –

+0

И сколько экземпляров прототипа будет иметь ваш список? –

ответ

1

А как насчет использования фасоли?

Я знаю, что вы упомянули, что не хотите быть слишком привязанным к весне - с фабричной фасолью ваш фасоль, содержащая список, не так соединен - ​​только ваша фабрика.

Что-то вроде

@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(); 
     } 
    } 
} 

не пробовал сам, или был сценарий, когда я нуждался в этом, так что я не уверен, что он будет работать.

+0

С подробностями, которые вы нам дали, ОП, я думаю, что это правильное решение. Просто имейте в виду, что если вы позже создадите новые фаны Foo, они не будут добавлены в список FooClient. –

0

Если вы делаете это в коде непосредственно, то я думаю, что с помощью PostConstruct аннотацию бы путь:

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

.... 

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

Я думаю, используя этот подход будет более гибким, так как я думаю, что вы будет бороться с аннотациями, только если сами объекты FooImpl требуют дополнительной настройки.

+0

Дело в том, что это так, но у меня есть метод 'init', чтобы справиться с этим (пока я не получу лучшую идею). –

0

Это ограничение (или особенность) prototype scope. The docs say this

В отличие от других областей, Spring не удается полностью жизненный цикл прототипа боба: контейнер создает экземпляр, настраивает и иным образом собирает объект прототипа, и передает его клиенту , с никакой дополнительной записи этого экземпляра прототипа.

Итак, после того, как весна передаст вам это, он не будет ссылаться на него и, следовательно, не может автоподвести ни один из них в ваш fooList. Если вы сделали добавить @Autowired

@Autowired 
private List<Foo> fooList; 

было бы просто создать новый объект FooImpl и autowire, что в качестве одного элемента в вашем List.

Если вы пытаетесь сохранить ссылку на все созданные вами Foo экземпляры, вам, скорее всего, придется это сделать самостоятельно.

+0

Так что мне нужен какой-то заводский метод, который возвращает новый экземпляр компонента, который я хочу/нуждаюсь в * запросах вручную *. Есть ли хороший подход, который не связан с конфигурацией XML или непосредственным использованием «BeanFactory» в моем классе? –

+0

@LuiggiMendoza Проблема заключается в том, что оба ваших компонента являются «прототипами» beans, поэтому в любое время, когда вы запрашиваете их, вы получите новый экземпляр. Можете ли вы подробнее рассказать о том, чего вы пытаетесь достичь? –

+0

Я хочу заполнить список моего интерфейса Foo с помощью прототипов beans. Так просто. Это часть решения для улучшения процесса. Чтобы добавить несколько потоков в решение, я должен создать больше экземпляров 'Foo', по одному на поток, чтобы избежать проблем с несколькими потоками, обращающимися к тем же ресурсам (что объясняет использование прототипов). –

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>         
Смежные вопросы