Как использовать CDI для ввода параметров метода?

Можно ли использовать CDI для ввода параметров в вызовы методов? Ожидаемое поведение будет похоже на инъекцию поля. Выбранный производитель просматривается и продукт используется.

Что я хотел бы сделать, так это:

public void foo(@Inject Bar bar){
  //do stuff
} 

или это (с менее запутанным sytax):

public void foo(){
  @Inject 
  Bar bar;
  //do stuff
} 

Этот синтаксис в обоих случаях является незаконным. Есть ли альтернатива? Если нет - было бы это плохой идеей по какой-либо причине, если бы это было возможно?

Спасибо

EDIT. Возможно, мои требования недостаточно ясны - я хотел бы иметь возможность напрямую вызвать метод, оставив инициализацию переменной bar в контейнере. Йорн Хорстманн и ответ "Восприятие" предполагают, что это невозможно.

Ответы

Ответ 1

Точки инъекции обрабатываются для bean, когда он создается экземпляром контейнера, что ограничивает количество случаев использования для инъекции уровня метода. Текущая версия спецификации распознает следующие типы инъекций метода:

Включение метода инициализатора

public class MyBean {
    private Processor processor;

    @Inject
    public void setProcessor(final Processor processor) {
        this.processor = processor;
    }
}

Когда вводится экземпляр MyBean, экземпляр процессора также будет инъецирован через его метод setter.

Методы наблюдения за событиями

public class MyEventHandler {
    public void processSomeEvent(@Observes final SomeEvent event) {
    }
}

Экземпляр события вводится непосредственно в метод обработки событий (хотя и не с аннотацией @Inject)

Методы производителя

public class ProcessorFactory {
    @Produces public Processor getProcessor(@Inject final Gateway gateway) {
        // ...
    }
}

Параметры для методов производителя автоматически вводятся.

Ответ 2

Если то, что вы действительно хотите, не является чем-то параметром метода (который должен быть предоставлен вызывающим), но правильно инициализированным экземпляром CDI bean каждый раз, когда метод вызывается и полностью сконструирован и вставляют, затем проверяем

javax.inject.Provider<T>

В принципе, сначала введите поставщика в класс

@Inject Provider<YourBean> yourBeanProvider;

то в этом методе получите новый экземпляр

YourBean bean = yourBeanProvider.get();

Надеюсь, что это поможет:)

Ответ 3

Эта функция CDI называется "методом инициализации". Синтаксис отличается от вашего кода тем, что весь метод аннотируется с помощью @Inject, параметры метода могут быть дополнительно аннотированы квалификаторами для выбора конкретного bean. Раздел 3.9 JSR 299 показывает следующий пример: @Selected - это классификатор, который можно опустить, если существует только одна реализация bean.

@Inject
void setProduct(@Selected Product product) {
    this.product = product;
}

Обратите внимание, что

Приложение может напрямую обращаться к методам инициализации, но затем никакие параметры не будут переданы этому контейнеру.

Ответ 4

Этот вопрос возник, когда я изначально сделал поиск по этой теме, и с тех пор я узнал, что с выпуском CDI 1.1 (включенного в спецификацию JavaEE 7) теперь есть способ сделать то, что хотел OP, частично. Вы все еще не можете делать

public void foo(@Inject Bar bar){
   //do stuff
}

но вы можете "ввести" локальную переменную, хотя вы не используете @Inject, а скорее программно просматриваете введенный экземпляр следующим образом:

public void foo() {
    Instance<Bar> instance = CDI.current().select(Bar.class);
    Bar bar = instance.get();
    CDI.current().destroy(instance);
    // do stuff with bar here
}

Обратите внимание, что метод select() необязательно принимает любые аннотации классификаторов, которые вам могут потребоваться. Удачи в получении экземпляров java.lang.annotation.Annotation, хотя. Возможно, вам легче прокрутить ваш Instance<Bar>, чтобы найти тот, который вы хотите.

Мне сказали, что вам нужно уничтожить Instance<Bar>, как я уже говорил выше, и проверить на опыте, что приведенный выше код работает; однако я не могу поклясться, что вам нужно его уничтожить.

Ответ 5

Вы можете использовать API-интерфейс BeanManager в своем методе для получения контекстных ссылок или в зависимости от вашей конечной цели вы можете ввести

Instance<Bar>

вне метода и использовать его в методе.