Как использовать 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>
вне метода и использовать его в методе.