2013-02-25 3 views
11

Предположим, у меня есть класс Car. В моем коде я хочу создать 10 автомобилей. Класс Car имеет некоторые аннотированные зависимости @Inject. Какой был бы лучший подход для этого?Как создавать экземпляры «на лету» в CDI

CDI имеет интерфейс провайдера, который я могу использовать для создания автомобилей:

@Inject Provider<Car> carProvider; 
public void businessMethod(){ 
    Car car = carProvider.get(); 
} 

К сожалению, это не работает, если у меня нет CarFactory, который имеет метод с @Produces аннотацией, которая создает автомобиль. Насколько он отражает реальный мир, что я не могу создавать автомобили без завода, я бы предпочел не писать заводы для всего. Я просто хочу, чтобы контейнер CDI создавал мою машину так же, как и любой другой компонент. Как вы рекомендуете создавать эти автомобили?

ответ

8

Просто используйте вместо этого интерфейс javax.enterprise.inject.Instance.

Как это:

public class Bean { 

    private Instance<Car> carInstances; 

    @Inject 
    Bean(@Any Instance<Car> carInstances){ 
     this.carInstances = carInstances; 
    } 

    public void use(){ 
     Car newCar = carInstances.get(); 
     // Do stuff with car ... 
    } 

} 
+0

Это на самом деле то, что я использовал.Не могли бы вы исправить свой пример, аргумент конструктора не такой же, как атрибут класса: Car vs UIModule. Также я думаю, что инъекция должна быть аннотированной с помощью @New вместо @Any. И лучшим примером для метода use() будет тот, который показал бы, как вы получите экземпляр автомобиля. Например, 'carInstances.get()' – palto

+0

@New устарел в CDI 1.1, предпочитая @Dependent beans. См. CDI 1.1, раздел 3.14. Я не понимаю, что случилось с использованием провайдера, т.е. e., 'CDI.current(). select (Car.class) .get()'? –

+0

@MartinAndersson Первоначальная проблема заключалась в том, что мне пришлось создать фабрику для использования провайдера. Пример, который вы указали в комментарии, для меня совершенно незначителен. Может быть, вы могли бы создать ответ? – palto

2

Вы можете использовать определители с @Produces аннотаций:

@Qualifier 
@Retention(RetentionPolicy.RUNTIME) 
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER}) 
public @interface MyCars { 
} 

образец-производитель-метод:

@Produces 
@MyCars 
public Car getNewCar(@New Car car){ 
    return car; 
} 

использование:

@Inject 
@MyCars 
private Provider<Car> carProvider; 
+0

«@New устарел в CDI 1.1, предпочитая @Dependent beans. См. CDI 1.1, раздел 3.14. –

+0

@MartinAndersson я знаю это, но поскольку время ответа CDI 1.1 не было, так что ответ идет на CDI 1.0 (просто для того, чтобы уточнить это здесь). – FibreFoX

0

Другой способ сделать это было бы просто не дать Car любой объем CDI, что делает его зависимым, и вы получите новый экземпляр каждый раз, когда его вводят, и tho se экземпляры не будут уничтожены до уничтожения содержащего экземпляра.

+0

сфера не о чем беспокоиться, насколько я что он хочет иметь внедренного производителя и не должен внедрять определенный класс-производитель. Вы правы, что все введенные cdi-beans становятся '@ зависимыми', но не то, что палто говорил о – FibreFoX

+0

« новый экземпляр каждый раз, когда он вводится »? Как можно вводить зависимого «каждый раз»? Инъекция происходит только один раз. Прокси. Если был добавлен компонент @Dependent или прокси-сервер, каждый вызов этого прокси-сервера всегда будет перенаправляться на один и тот же бэк-компонент. –

+0

Он вводит прокси-сервер один раз, да, но если этот прокси-сервер разрешает зависимый фасонный компонент, то этот зависимый фасонный элемент создается новым для каждого нового экземпляра компонента, запрашивающего инъекцию. Инжектируемый компонент становится зависимым от жизненного цикла другого. – LightGuard

5

Моя любимая модель для программного поиска является использование CDI.current().select().get().

Демонстрировано here.

сервлет имеет зависимость от двух бобов CDI, один запрос и область действия другого приложения область действия:

private final RequestScopedBean requestScoped 
      = CDI.current().select(RequestScopedBean.class).get(); 

private final ApplicationScopedBean applicationScoped 
      = CDI.current().select(ApplicationScopedBean.class).get(); 

тест класс, который использует этот сервлет можно найти here.

Изучите код, и вы заметите, что код полностью эквивалентен тому, что вы получите, используя @Inject MyBean myBean;.