Это второй пост, основанный на чистой инъекции CDI (см. Часть I ) после того, как мы поговорили о том, как загрузить CDI в нескольких средах и как добавить CDI в существующее приложение Java EE 6 . В этом посте я быстро хочу показать различные точки внедрения в CDI: поле, конструктор и сеттер . Чтобы проиллюстрировать эти разные точки внедрения, я буду использовать подмножество предыдущего примера : сервлет, внедряющий генератор ISBN POJO :
Полевая инъекция
До сих пор во всех предыдущих постах вы видели аннотацию @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;
}
...
}
Но правило таково: у вас может быть только одна точка инжекции конструктора . Контейнер выполняет инъекцию, а не вы (вы не можете вызвать конструктор в управляемой среде, ну, вы можете, но он не будет работать так, как вы ожидаете). Разрешен только один конструктор bean-компонента, поэтому контейнер может выполнять свои функции, вставляя правильные ссылки. Следующее недействительно :
@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;
}
...
}
Если у вас есть более одного компонента bean-компонента, это то, что вы получаете (код ошибки и сообщение, конечно, специфичны для 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;
}
...
}
Когда вы используете инжектор конструктора или сеттера, вам нужно применить свои квалификаторы к параметру. Поэтому убедитесь, что у вас есть правильное определение @Targets (java.lang.annotation.ElementType.PARAMETER):
@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD, PARAMETER})
public @interface ThirteenDigits {
}
Вывод
Один вопрос, который вы могли бы задать (и это тот вопрос, который я задал Питу Мьюру ): «когда вы используете поле над конструктором или сеттером?». Там нет реального технического ответа, кроме того, что это ваш личный вкус. В управляемой среде контейнер — это тот, кто выполняет всю инъекцию, ему просто нужны правильные точки впрыска. Тем не менее, с помощью инжектора конструктора или сеттера вы можете добавить некоторую логику, если это необходимо (не с помощью инжекции поля). Но похоже, что добавление сеттера было добавлено для обратной совместимости с существующими компонентами Java .
В следующей статье будут рассмотрены альтернативы и производители , так что следите за обновлениями.
Скачать
Загрузите код , попробуйте и дайте мне обратную связь.
Рекомендации
С http://agoncal.wordpress.com/2011/05/03/injection-with-cdi-part-ii/