- PVSM.RU - https://www.pvsm.ru -
Это второй пост о внедрении зависимостей в CDI (Часть 1 [1]) после нашего разговора о том, как начать работу с CDI [2] в вашем окружении и как интегрировать CDI в существующее Java EE 6 приложение [3]. В этом посте я хочу рассказать о различных точках внедрения в CDI: поле, конструктор и сеттер. Для этого я буду использовать часть предыдущего примера: внедрение POJO генератора ISBN в сервлет.
Во всех предыдущих примерах вы видели аннотации @Inject
, привязанные к полям (атрибутам) класса.
@WebServlet(urlPatterns = "/itemServlet")
public class ItemServlet extends HttpServlet {
@Inject
@ThirteenDigits
private NumberGenerator numberGenerator;
@Inject
private ItemEJB itemEJB;
...
}
Как вы видите в представленном коде, аннотацией @Inject
и спецификатором (здесь @ThirteenDigits
) помечен атрибут. Но, как и во многих других фреймворках по внедрению зависимостей, в CDI вы можете проводить внедрение через конструктор или сеттер.
Вместо атрибутов вы можете добавить аннотацию @Inject
к конструктору. Если же вам необходимо специфированное внедрение, то вы можете пометить спецификатором параметр конструктора:
@WebServlet(urlPatterns = "/itemServlet")
public class ItemServlet extends HttpServlet {
private NumberGenerator numberGenerator;
private ItemEJB itemEJB;
@Inject
public ItemServlet(@ThirteenDigits NumberGenerator numberGenerator, ItemEJB itemEJB) {
this.numberGenerator = numberGenerator;
this.itemEJB = itemEJB;
}
...
}
Как вы видите, в данном случае аннотацией @Inject
помечен не атрибут класса, а конструктор. С другой стороны, @ThirteenDigits
помечает не конструктор, а его параметр numberGenerator
(что логично). Если захотите, вы можете смешивать внедрение через поле и через конструктор (ниже я использую внедрение через конструктор и атрибут для EJB):
@WebServlet(urlPatterns = "/itemServlet")
public class ItemServlet extends HttpServlet {
private NumberGenerator numberGenerator;
@Inject
private ItemEJB itemEJB;
@Inject
public ItemServlet(@ThirteenDigits NumberGenerator numberGenerator) {
this.numberGenerator = numberGenerator;
}
...
}
Но есть правило: у вас может быть только один конструктор с внедрением. Контейнер выполняет внедрение, не вы (вы, конечно, можете вызывать конструктор в управляемой среде, но он не будет работать так, как вы ожидаете). И есть только один конструктор бина, позволяющий контейнеру выполнить корректное внедрение всех зависимостей. Следующий код некорректный:
@WebServlet(urlPatterns = "/itemServlet")
public class ItemServlet extends HttpServlet {
private NumberGenerator numberGenerator;
private ItemEJB itemEJB;
@Inject
public ItemServlet(@ThirteenDigits NumberGenerator numberGenerator, ItemEJB itemEJB) {
this.numberGenerator = numberGenerator;
this.itemEJB = itemEJB;
}
@Inject
public ItemServlet(@ThirteenDigits NumberGenerator numberGenerator) {
this.numberGenerator = numberGenerator;
}
...
}
Если у вас более одного конструктора в бине, вот что вы получите (код и сообщение об ошибке, конечно, специфичны для Weld)
WELD-000812 Cannot determine constructor to use for public@WebServlet class ItemServlet. Possible constructors [[constructor] @Inject public ItemServlet(NumberGenerator, ItemEJB), [constructor] @Inject public ItemServlet(NumberGenerator)]
Да, синтаксически допустимо проводить внедрение через поле и конструктор одновременно, но смысла в этом нет:
@WebServlet(urlPatterns = "/itemServlet")
public class ItemServlet extends HttpServlet {
@Inject @ThirteenDigits
private NumberGenerator numberGenerator;
@Inject
private ItemEJB itemEJB;
@Inject
public ItemServlet(@ThirteenDigits NumberGenerator numberGenerator, ItemEJB itemEJB) {
this.numberGenerator = numberGenerator;
this.itemEJB = itemEJB;
}
...
}
Есть другой способ — это использовать внедрение через сеттер, которое выглядит как внедрение через конструктор. Аннотацией @Inject
вы помечаете сам сеттер, а спецификаторами — его аргументы:
@WebServlet(urlPatterns = "/itemServlet")
public class ItemServlet extends HttpServlet {
private NumberGenerator numberGenerator;
private ItemEJB itemEJB;
@Inject
public void setNumberGenerator(@ThirteenDigits NumberGenerator numberGenerator) {
this.numberGenerator = numberGenerator;
}
@Inject
public void setItemEJB(ItemEJB itemEJB) {
this.itemEJB = itemEJB;
}
...
}
Когда вы используете внедрение через конструктор или сеттер, вам необходимо специфицировать аргументы. Поэтому убедитесь, что у вас правильно объявлен @Target(java.lang.annotation.ElementType.PARAMETER)
:
@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD, PARAMETER})
public @interface ThirteenDigits {
}
У вас может возникнуть один вопрос (и я его [4] тоже задал Pete Muir [5]): когда нужно использовать ту или иную точку внедрения? Но на этот вопрос нет технического ответа, это дело личного вкуса. В управляемой среде только контейнер выполняет внедрение, и всё, что ему нужно — это корректные точки внедрения. Однако в случае внедрения через конструктор или сеттер, при необходимости вы можете добавить какую-то логику (что невозможно при внедрении через атрибуты). Но, похоже, что внедрение через сеттеры было добавлено, скорее, для обратной совместимости с уже созданными Java Beans [6].
В следующей статье я расскажу о продюсерах [7].
Скачайте код [8] и расскажите, что вы о нем думаете.
Автор: AT Consulting
Источник [9]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/java/129051
Ссылки в тексте:
[1] Часть 1: https://habrahabr.ru/company/at_consulting/blog/301636/
[2] начать работу с CDI: https://antoniogoncalves.org/2011/01/12/bootstrapping-cdi-in-several-environments/
[3] интегрировать CDI в существующее Java EE 6 приложение: https://antoniogoncalves.org/2011/02/07/adding-cdi-to-an-existing-java-ee-6-application/
[4] его: http://twitter.com/#!/agoncal/status/65166255216279553
[5] Pete Muir: http://twitter.com/#!/plmuir/status/65196933928595456
[6] для обратной совместимости с уже созданными Java Beans: http://twitter.com/#!/plmuir/statuses/65497453637550080
[7] продюсерах: https://habrahabr.ru/company/at_consulting/blog/302010/
[8] Скачайте код: https://github.com/agoncal/agoncal-sample-cdi
[9] Источник: https://habrahabr.ru/post/301768/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.