| // |
| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // |
| |
| = Работа с внедрением и квалификаторами в CDI |
| :jbake-type: tutorial |
| :jbake-tags: tutorials |
| :jbake-status: published |
| :icons: font |
| :syntax: true |
| :source-highlighter: pygments |
| :toc: left |
| :toc-title: |
| :description: Работа с внедрением и квалификаторами в CDI - Apache NetBeans |
| :keywords: Apache NetBeans, Tutorials, Работа с внедрением и квалификаторами в CDI |
| |
| _Предоставлено Энди Гибсоном (Andy Gibson)_ |
| |
| |
| === Внедрение контекстов и зависимостей |
| |
| 1. link:cdi-intro.html[+Введение в CDI и JSF 2.0+] |
| 2. *Работа с внедрением и квалификаторами в CDI* |
| * <<inject,Внедрение: основной этап CDI>> |
| * <<qualifier,Работа с квалификаторами>> |
| * <<alternative,Альтернативные методы внедрения>> |
| * <<seealso,Дополнительные сведения>> |
| 3. link:cdi-validate.html[+Применение аннотации @Alternative и аннотаций жизненного цикла+] |
| 4. link:cdi-events.html[+Обработка событий в CDI+] |
| |
| image::images/netbeans-stamp-80-74-73.png[title="Содержимое этой страницы применимо к IDE NetBeans 7.2, 7.3, 7.4 и 8.0"] |
| |
| Внедрение контекстов и зависимостей (CDI), определяемое документом link:http://jcp.org/en/jsr/detail?id=299[+JSR-299+], является неотъемлемой частью Java EE 6 и обеспечивает архитектуру, позволяющую компонентам Java EE (например, сервлетам, компонентам EJB и JavaBeans) существовать в жизненном цикле приложения с четко определенными контекстами. Кроме того, службы CDI позволяют компонентам Java EE (например, компонентам сеансов EJB и управляемым компонентам JavaServer Faces) внедряться и свободно взаимодействовать путем запуска и обработки событий. |
| |
| Этот учебный курс основан на записи блога Энди Гибсона (Andy Gibson) link:http://www.andygibson.net/blog/index.php/2009/12/22/getting-started-with-cdi-part-2-injection/[+Начало работы с CDI. Часть 2. Внедрение+]. Здесь рассматриваются способы использования внедрения CDI для _ввода_ классов или интерфейсов в другие классы. Кроме того, здесь показаны способы применения _квалификаторов_ CDI для кода, которые позволяют определить тип класса, который необходимо внедрить в указанной точке внедрения. |
| |
| В NetBeans IDE обеспечена встроенная поддержка для внедрения контекстов и зависимостей, включая поддержку создания файла конфигурации CDI `beans.xml` при создании проекта, поддержку редактора и навигации для аннотаций, а также различных мастеров для создания часто используемых артефактов CD. |
| |
| |
| Для работы с этим учебным курсом требуется программное обеспечение и материалы, перечисленные ниже. |
| |
| |=== |
| |Программное обеспечение или материал |Требуемая версия |
| |
| |link:https://netbeans.org/downloads/index.html[+IDE NetBeans+] |Версия 7.2, 7.3, 7.4, 8.0, Java EE |
| |
| |link:http://www.oracle.com/technetwork/java/javase/downloads/index.html[+Комплект для разработчика на языке Java (JDK)+] |версия 7 или 8 |
| |
| |link:http://glassfish.dev.java.net/[+Сервер GlassFish+] |Open Source Edition 3.x или 4.x |
| |
| |link:https://netbeans.org/projects/samples/downloads/download/Samples%252FJavaEE%252FcdiDemo.zip[+cdiDemo.zip+] |неприменимо |
| |=== |
| |
| *Примечания.* |
| |
| * В комплект Java для IDE NetBeans также входит компонент GlassFish Server Open Source Edition, являющийся контейнером, совместимым с Java EE. |
| * Пример решения для этого учебного курса можно загрузить здесь: link:https://netbeans.org/projects/samples/downloads/download/Samples%252FJavaEE%252FcdiDemo2.zip[+cdiDemo2.zip+] |
| |
| |
| |
| [[inject]] |
| == Внедрение: основной этап CDI |
| |
| CDI является интерфейсом API для внедрения контекстов и зависимостей. В платформах приложений Seam и Spring зависимости обычно основаны на принципе присвоения имен компонентам, а также на привязке компонентов к точкам внедрения по именам. При переходе к этому учебному курсу по завершении link:cdi-intro.html[+Начало работы с внедрением контекстов и зависимостей и JSF 2.0+] код пока содержит только ссылку на управляемый компонент по имени со страницы JSF, которая была создана после того, как мы определили имя компонента с помощью аннотации `@Named`. Основная роль аннотации `@Named` заключается в определении компонента для разрешения операторов языка выражений в приложении (обычно с помощью средств разрешения языка выражений JSF). Внедрение _можно было бы_ реализовать посредством использования имен, но внедрение в CDI обычно выполняется иначе, так как CDI предлагает лучшее решение для выражения точек внедрения и компонентов, которые необходимо внедрить в эти точки. |
| |
| В следующем примере создается класс `ItemProcessor`, который принимает список элементов из класса, реализующего интерфейс `ItemDao`. Аннотация `@Inject` CDI используется для демонстрации возможности _внедрения_ компонента в другой класс. На диаграмме ниже показан сценарий, создаваемый в этом упражнении. |
| |
| image::images/cdi-diagram-inject.png[title="Используйте внедрение CDI для свободного взаимодействия классов в используемом приложении"] |
| |
| DAO - это _объект доступа к данным_. |
| |
| 1. Сначала необходимо извлечь пример начального проекта из файла `cdiDemo.zip` (см. выше <<requiredSoftware,таблицу с перечислением требуемых ресурсов>>). Выберите File ("Файл") > Open Project ("Открыть проект") (Ctrl-Shift-O; ⌘-Shift-O on Mac) и выберите проект в его местоположении на компьютере. |
| 2. Щелкните правой кнопкой мыши узел проекта в окне "Проекты" и выберите команду "Свойства". |
| 3. Выберите категорию "Запуск" и убедитесь, что в списке "Сервер" выбран экземпляр GlassFish. |
| 4. Создайте новый класс `Item` и сохраните его в новом пакете с именем `exercise2`. Щелкните 'Создать файл' ( image::images/new-file-btn.png[] ) или нажмите сочетание клавиш CTRL+N (⌘-N on Mac) для открытия мастера создания файлов. |
| 5. Выберите категорию Java, а затем выберите класс Java. Нажмите кнопку "Далее". |
| 6. Введите *Item* в качестве имени класса, затем укажите *exercise2* в качестве пакета. Новый пакет будет создан после завершения работы мастера. |
| image::images/java-class-wizard.png[title="Среда IDE может помочь в этом, предоставляя мастер библиотеки классов Java."] |
| 7. Нажмите кнопку "Завершить". Выполняется создание нового класса и пакета, и класс `Item` открывается в редакторе. |
| 8. Создайте свойства `value` и `limit` для POJO `Item` и реализуйте метод `toString()`. Добавьте следующее содержимое к классу. |
| |
| [source,java] |
| ---- |
| |
| public class Item { |
| |
| *private int value; |
| private int limit; |
| |
| @Override |
| public String toString() { |
| return super.toString() + String.format(" [Value=%d, Limit=%d]", value,limit); |
| }* |
| } |
| ---- |
| 9. Добавьте методы получения и установки к классу. Для этого убедитесь, что курсор размещен в определении класса (т.е. между фигурными скобками класса), затем щелкните в редакторе правой кнопкой мыши и выберите пункт "Вставить код" (ALT+INSERT; CTRL+I на компьютерах Mac). Выберите методы получения и установки. |
| image::images/insert-code.png[title="Создайте методы получения и установки с помощью всплывающего окна 'Вставить код'"] |
| 10. Установите флажок `Item` (при этом выбираются все свойства, содержащиеся в классе). |
| image::images/generate-getters-setters.png[title="Установите флажок для класса для выбора всех свойств, содержащихся в классе"] |
| 11. Нажмите кнопку "Создать". Для класса создаются методы получения и установки. |
| |
| [source,java] |
| ---- |
| |
| public class Item { |
| |
| private int value; |
| private int limit; |
| |
| *public int getLimit() { |
| return limit; |
| } |
| |
| public void setLimit(int limit) { |
| this.limit = limit; |
| } |
| |
| public int getValue() { |
| return value; |
| } |
| |
| public void setValue(int value) { |
| this.value = value; |
| }* |
| |
| @Override |
| public String toString() { |
| return super.toString() + String.format(" [Value=%d, Limit=%d]", value, limit); |
| } |
| } |
| ---- |
| 12. Создайте конструктор, который принимает оба аргумента `value` и `limit`. Кроме того, для этого можно использовать IDE. Нажмите сочетание клавиш CTRL+ПРОБЕЛ в определении класса и выберите параметр "`Item(int value, int limit) - generate`". |
| image::images/generate-constructor.png[title="Нажмите сочетание клавиш CTRL+ПРОБЕЛ, чтобы использовать функцию автозавершения кода в редакторе."] |
| К классу добавляется следующий конструктор. |
| |
| [source,java] |
| ---- |
| |
| public class Item { |
| |
| *public Item(int value, int limit) { |
| this.value = value; |
| this.limit = limit; |
| }* |
| |
| private int value; |
| private int limit; |
| |
| ... |
| ---- |
| 13. Создайте интерфейс `ItemDao` для определения способа получения списка объектов `Item`. В этом тестовом приложении мы допускаем использование нескольких реализаций, следовательно, создаем код для интерфейсов. |
| |
| Щелкните 'Создать файл' ( image::images/new-file-btn.png[] ) или нажмите сочетание клавиш CTRL+N (⌘-N on Mac) для открытия мастера создания файлов. |
| |
| 14. Выберите категорию Java, а затем команду "Интерфейс Java". Нажмите кнопку "Далее". |
| 15. Введите *ItemDao* в качестве имени класса, затем укажите *exercise2* в качестве пакета. |
| 16. Нажмите кнопку "Завершить". Интерфейс будет создан и открыт в редакторе. |
| 17. Добавьте метод с именем `fetchItems()`, который возвращает элемент `List` объектов `Item`. |
| |
| [source,java] |
| ---- |
| |
| public interface ItemDao { |
| |
| *List<Item> fetchItems();* |
| |
| } |
| ---- |
| Используйте подсказку редактора, чтобы добавить оператор импорта для `java.util.List`. |
| 18. Создайте класс `ItemProcessor`. Это главный класс для внедрения базовых элементов и выполнения процесса. базовый элемент. |
| |
| Щелкните 'Создать файл' ( image::images/new-file-btn.png[] ) или нажмите сочетание клавиш CTRL+N (⌘-N on Mac) для открытия мастера создания файлов. |
| |
| 19. Выберите категорию Java, а затем выберите класс Java. Нажмите кнопку "Далее". |
| 20. Введите *ItemProcessor* в качестве имени класса, затем укажите *exercise2* в качестве пакета. Нажмите кнопку "Завершить". |
| |
| В редакторе будет создан и открыт новый класс. |
| |
| 21. Измените класс следующим образом: |
| |
| [source,java] |
| ---- |
| |
| @Named |
| @RequestScoped |
| public class ItemProcessor { |
| |
| private ItemDao itemDao; |
| |
| public void execute() { |
| List<Item> items = itemDao.fetchItems(); |
| for (Item item : items) { |
| System.out.println("Found item " + item); |
| } |
| } |
| } |
| ---- |
| 22. Исправьте операторы импорта. Либо щелкните правой кнопкой мыши в редакторе и выберите 'Исправить выражения импорта' или нажмите Ctrl-Shift-I (⌘-Shift-I в Mac). |
| image::images/fix-imports.png[title="Щелкните в редакторе правой кнопкой мыши и выберите 'Исправить операторы импорта' для добавления операторов импорта к классу"] |
| 23. Нажмите кнопку "ОК". Операторы импорта требуются для следующих классов: |
| * `java.util.List` |
| * `javax.inject.Named` |
| * `javax.enterprise.context.RequestScoped` |
| 24. Начните с простого DAO, который только создает список элементов и возвращает фиксированный список элементов. |
| |
| В окне "Проекты" щелкните правой кнопкой мыши узел пакета `exercise2` и выберите "Создать > Класс Java". В мастере создания класса Java присвойте классу имя `DefaultItemDao`. Нажмите кнопку "Завершить". image::images/java-class-wizard2.png[title="Создайте новый класс Java с помощью мастера классов Java"] |
| 25. Необходимо, чтобы в редакторе элемент `DefaultItemDao` реализовывал интерфейс `ItemDao` и обеспечивал реализацию `fetchItems()`. |
| |
| [source,java] |
| ---- |
| |
| public class DefaultItemDao *implements ItemDao* { |
| |
| *@Override |
| public List<Item> fetchItems() { |
| List<Item> results = new ArrayList<Item>(); |
| results.add(new Item(34, 7)); |
| results.add(new Item(4, 37)); |
| results.add(new Item(24, 19)); |
| results.add(new Item(89, 32)); |
| return results; |
| }* |
| } |
| ---- |
| Нажмите сочетание клавиш Ctrl-Shift-I (⌘-Shift-I on Mac) для добавления операторов импорта для `java.util.List` and `java.util.ArrayList`. |
| 26. Перейдите к классу `ItemProcessor` (нажмите сочетание клавиш CTRL+TAB). Чтобы внедрить `DefaultItemDao` в `ItemProcessor` добавляется аннотация `javax.inject.Inject` к полю `ItemDao` для указания того, что это поле является точкой внедрения. |
| |
| [source,java] |
| ---- |
| |
| *import javax.inject.Inject;* |
| ... |
| |
| @Named |
| @RequestScoped |
| public class ItemProcessor { |
| |
| *@Inject* |
| private ItemDao itemDao; |
| |
| ... |
| } |
| ---- |
| [tips]#Используйте поддержку автозавершения кода редактора для добавления аннотации `@Inject` и оператора импорта к классу. Например, введите `@Inj`, а затем нажмите CTRL+ПРОБЕЛ.# |
| 27. Наконец, необходим способ для вызова метода `execute()` в `ItemProcessor`. Это можно выполнить в среде SE, но сейчас мы сделаем это на странице JSF. Создайте новую страницу с именем `process.xhtml`, которая содержит кнопку для вызова метода `execute()`. |
| |
| Щелкните 'Создать файл' ( image::images/new-file-btn.png[] ) или нажмите сочетание клавиш CTRL+N (⌘-N on Mac) для открытия мастера создания файлов. |
| 28. Выберите категорию JavaServer Faces, затем выберите страницу JSF. Нажмите кнопку "Далее". |
| 29. Введите *process* в качестве имени файла, затем нажмите кнопку "Готово". |
| image::images/new-jsf-page.png[title="Создайте новую страницу Facelets с помощью мастера файлов JSF"] |
| 30. В новом файле `process.xhtml` добавьте кнопку, которая привязана к методу `ItemProcessor.execute()`. При использовании языка выражений имя по умолчанию для управляемого компонента является таким же, как имя класса, но первая буква в нижнем регистре (т.е. `itemProcessor`). |
| |
| [source,xml] |
| ---- |
| |
| <h:body> |
| *<h:form> |
| <h:commandButton action="#{itemProcessor.execute}" value="Execute"/> |
| </h:form>* |
| </h:body> |
| ---- |
| 31. Перед выполнением проекта установите файл `process.xhtml` в качестве новой страницы приветствия в дескрипторе развертывания веб-приложения. |
| |
| Используйте диалоговое окно среды IDE "Переход к файлу" для быстрого открытия файла `web.xml`. В основном меню среды IDE выберите "Переход > Перейти к файлу" (ALT+SHIFT+O; CTRL+SHIFT+O на компьютерах Mac), а затем введите `web`. |
| image::images/go-to-file.png[title="С помощью диалогового окна "Переход к файлу" быстро найдите файл проекта"] |
| 32. Нажмите кнопку "ОК". В представлении XML для файла `web.xml` выполните следующие изменения. |
| |
| [source,xml] |
| ---- |
| |
| <welcome-file-list> |
| <welcome-file>faces/*process.xhtml*</welcome-file> |
| </welcome-file-list> |
| ---- |
| 33. Нажмите кнопку 'Запустить проект' (image::images/run-project-btn.png[]) на главной панели инструментов IDE. Проект компилируется и развертывается на GlassFish, и файл `process.xhtml` открывается в браузере. |
| 34. Нажмите кнопку `Выполнить` на странице. Вернитесь в среду IDE и проверьте протокол сервера GlassFish. Журнал сервера отображается в окне вывода (Ctrl-4; ⌘-4 в Mac) на вкладке 'Сервер GlassFish'. При нажатии кнопки журнал выводит список элементов из реализации DAO по умолчанию. |
| image::images/output-window.png[title="Проверьте журнал сервера в окне вывода IDE"] |
| [tips]#Щелкните правой кнопкой мыши окно вывода и выберите 'Очистить' (Ctrl-L; ⌘-L в Mac) для очистки журнала. На изображении выше протокол очищен перед нажатием кнопки `Выполнить`.# |
| |
| Мы создали класс, который реализует интерфейс `ItemDao`, а при развертывании приложения наши управляемые компоненты в модуле обрабатывались посредством реализации CDI (на основании файла `beans.xml` в модуле). Наша аннотация `@Inject` указывает на то, что управляемый компонент необходимо внедрить в это поле, и единственная вещь, которую мы знаем о внедряемом компоненте заключается в том, что он должен реализовывать `ItemDao` или какой-либо подтип этого интерфейса. В этом случае класс `DefaultItemDao` полностью отвечает требованиям. |
| |
| Что может произойти при наличии нескольких реализаций внедряемого интерфейса `ItemDao`? CDI не сможет определить, какую реализацию необходимо выбрать, и выдаст ошибку во время развертывания. Для устранения этого необходимо использовать квалификатор CDI. Квалификаторы рассматриваются в следующем разделе. |
| |
| |
| |
| [[qualifier]] |
| == Работа с квалификаторами |
| |
| Квалификатором CDI является аннотация, которую можно применить на уровне класса, для указания, какой компонент является классом, а также на уровне поля (среди других расположений) для указания, какой компонент требуется для внедрения в этой точке. |
| |
| Чтобы продемонстрировать необходимость квалификатора в создаваемом приложении, добавим в это приложение другой класс DAO, который также реализует интерфейс `ItemDao`. На следующей диаграмме показан сценарий, создаваемый в этом упражнении. CDI должен уметь определять, какую реализацию компонента необходимо использовать в точке внедрения. Поскольку существует две реализации интерфейса `ItemDao`, эта задача решается посредством создания квалификатора с именем `Demo`. Затем мы "помечаем" используемый компонент, а также точку внедрения в `ItemProcessor` аннотаций `@Demo`. |
| |
| image::images/cdi-diagram-qualify.png[title="Используйте внедрение и квалификаторы CDI для свободного взаимодействия классов в используемом приложении"] |
| |
| Выполните следующие шаги. |
| |
| 1. В окне "Проекты" щелкните правой кнопкой мыши пакет `exercise2` и выберите "Создать > Класс Java". |
| 2. В мастере нового класса Java присвойте новому классу имя *AnotherItemDao*, а затем нажмите «Закончить». В редакторе будет создан и открыт новый класс. |
| 3. Измените класс, как указано ниже, чтобы он реализовывал интерфейс `ItemDao` и определял метод `fetchItems()` интерфейса. |
| |
| [source,java] |
| ---- |
| |
| public class AnotherItemDao *implements ItemDao* { |
| |
| *@Override |
| public List<Item> fetchItems() { |
| List<Item> results = new ArrayList<Item>(); |
| results.add(new Item(99, 9)); |
| return results; |
| }* |
| } |
| ---- |
| |
| Убедитесь, что добавлены операторы импорта для `java.util.List` и `java.util.ArrayList`. Для этого щелкните правой кнопкой мыши в редакторе и выберите 'Исправить выражения импорта' или нажмите Ctrl-Shift-I (⌘-Shift-I в Mac). |
| |
| Теперь, при наличии двух классов, которые внедряют`ItemDao`, не так ясно, какой базовый элемент необходимо внедрить. |
| |
| 4. Для запуска проекта нажмите кнопку 'Запустить проект' ( image::images/run-project-btn.png[] ). Обратите внимание, что теперь развертывание проекта завершается сбоем. |
| |
| Возможно, вам просто необходимо сохранить файл - IDE будет автоматически запускать проект, т.к. запуск при сохранении активирован по умолчанию. |
| |
| 5. Проверьте журнал сервера в окне вывода (Ctrl-4; ⌘-4 в Mac). Отобразится сообщение об ошибке, аналогичное следующему. |
| |
| [source,java] |
| ---- |
| |
| Caused by: org.jboss.weld.DeploymentException: Injection point has ambiguous dependencies. |
| Injection point: field exercise2.ItemProcessor.itemDao; |
| Qualifiers: [@javax.enterprise.inject.Default()]; |
| Possible dependencies: [exercise2.DefaultItemDao, exercise2.AnotherItemDao] |
| ---- |
| |
| Для переноса текста по словам в окне вывода щелкните правой кнопкой мыши и выберите команду "Перенос по словам". При этом не требуется горизонтальная прокрутка. |
| |
| Weld (реализация для CDI) выдает ошибку неоднозначной зависимости, означающую, что невозможно определить компонент, который необходимо использовать для указанной точки внедрения. Большинство ошибок, возникающих при внедрении CDI в Weld, регистрируются во время развертывания, даже если у компонентов в пассивном режиме отсутствует реализация `Serializable`. |
| |
| Полю `itemDao` в `ItemProcessor` можно присвоить определенный тип, который соответствует одному из типов реализации (`AnotherItemDao` или `DefaultItemDao`). В этом случае этот тип будет соответствовать только одному типу класса. Однако тогда мы потеряем преимущества кодирования интерфейса, а процедура изменения реализаций без изменения типа поля существенно усложнится. Лучшим решением являются квалификаторы CDI. |
| |
| Если CDI проверяет точку внедрения для поиска соответствующего внедряемого компонента, то учитывается не только тип класса, но и квалификаторы. Мы уже использовали квалификатор по умолчанию с именем `@Any`. Теперь создадим квалификатор `@Demo`, который можно применить для реализации `DefaultItemDao`, а также для точки внедрения в `ItemProcessor`. |
| |
| IDE предоставляет мастер, позволяющий создавать квалификаторы CDI. |
| |
| 6. Щелкните 'Создать файл' ( image::images/new-file-btn.png[] ) или нажмите сочетание клавиш CTRL+N (⌘-N on Mac) для открытия мастера создания файлов. |
| 7. Выберите категорию "Внедрение контекстов и зависимостей", затем выберите "Тип "квалификатора". Нажмите кнопку "Далее". |
| 8. Введите *Demo* в качестве имени класса, затем укажите *exercise2* в качестве пакета. |
| 9. Нажмите кнопку "Завершить". Новый квалификатор `Demo` открывается в редакторе. |
| |
| [source,java] |
| ---- |
| |
| package exercise2; |
| |
| import static java.lang.annotation.ElementType.TYPE; |
| import static java.lang.annotation.ElementType.FIELD; |
| import static java.lang.annotation.ElementType.PARAMETER; |
| import static java.lang.annotation.ElementType.METHOD; |
| import static java.lang.annotation.RetentionPolicy.RUNTIME; |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.Target; |
| import javax.inject.Qualifier; |
| |
| /** |
| * |
| * @author nbuser |
| */ |
| @Qualifier |
| @Retention(RUNTIME) |
| @Target({METHOD, FIELD, PARAMETER, TYPE}) |
| public @interface Demo { |
| } |
| ---- |
| |
| Затем этот квалификатор будет добавлен к реализатору DAO на уровне класса. |
| |
| 10. Перейдите в редакторе к `DefaultItemDao` (нажмите CTRL+TAB), а затем введите "`@Demo`" над определением класса. |
| |
| [source,java] |
| ---- |
| |
| *@Demo* |
| public class DefaultItemDao implements ItemDao { |
| |
| @Override |
| public List<Item> fetchItems() { |
| List<Item> results = new ArrayList<Item>(); |
| results.add(new Item(34, 7)); |
| results.add(new Item(4, 37)); |
| results.add(new Item(24, 19)); |
| results.add(new Item(89, 32)); |
| return results; |
| } |
| } |
| ---- |
| [tips]#После ввода `@` нажмите CTRL+ПРОБЕЛ для вызова предложений автозавершения кода. Редактор распознает квалификатор `Demo` и выводит `@Demo` в качестве параметра списка для автозавершения кода.# |
| 11. Для запуска проекта нажмите кнопку 'Запустить проект' ( image::images/run-project-btn.png[] ). Сборка и развертывание проекта выполняются без ошибок. |
| |
| *Примечание.* Для этого изменения может потребоваться явно запустить проект для повторного развертывания приложения вместо развертывания изменений с приращением. |
| |
| 12. В браузере нажмите кнопку `Выполнить`, затем вернитесь в среду IDE и проверьте протокол сервера в окне вывода. На экран будет выведено следующее. |
| |
| [source,java] |
| ---- |
| |
| INFO: Found item exercise2.Item@1ef62a93 [Value=99, Limit=9] |
| ---- |
| |
| Выводится позиция из класса `AnotherItemDao`. Следует помнить о том, что аннотирована реализация `DefaultItemDao`, но не точка внедрения в `ItemProcessor`. За счет добавления квалификатора `@Demo` к реализации DAO по умолчанию другая реализация стала более походящей для точки внедрения, поскольку она соответствует типу и квалификатору. `DefaultItemDao` имеет в настоящий момент квалификатор `Demo`, который расположен не в точке внедрения, что делает его менее подходящим. |
| |
| Затем вы добавите аннотацию `@Demo` к точке внедрения в`ItemProcessor`. |
| |
| 13. Перейдите в редакторе к `ItemProcessor` (нажмите CTRL+TAB), а затем выполните следующее изменение. |
| |
| [source,java] |
| ---- |
| |
| @Named |
| @RequestScoped |
| public class ItemProcessor { |
| |
| @Inject *@Demo* |
| private ItemDao itemDao; |
| |
| public void execute() { |
| List<Item> items = itemDao.fetchItems(); |
| for (Item item : items) { |
| System.out.println("Found item " + item); |
| } |
| } |
| } |
| ---- |
| 14. В браузере нажмите кнопку `Выполнить`, затем вернитесь в среду IDE и проверьте протокол сервера в окне вывода. На экран снова выводятся данные реализации по умолчанию (`DefaultItemDao`). |
| |
| [source,java] |
| ---- |
| |
| INFO: Found item exercise2.Item@7b3640f1 [Value=34, Limit=7] |
| INFO: Found item exercise2.Item@26e1cd69 [Value=4, Limit=37] |
| INFO: Found item exercise2.Item@3274bc70 [Value=24, Limit=19] |
| INFO: Found item exercise2.Item@dff76f1 [Value=89, Limit=32] |
| ---- |
| |
| Это произошло из-за сопоставления на основе типа_и_квалификаторов, а`DefaultItemDao`является единственным базовым элементом правильного типа и с аннотацией`@Demo`. |
| |
| |
| |
| [[alternative]] |
| == Альтернативные методы внедрения |
| |
| Существует несколько методов для определения точки внедрения во внедряемом классе. Пока вы проставили аннотации к полям, которые ссылаются на внедренный объект. Для внедрения поля не требуется методы получения и установки. Если вы хотите создать неизменяемые управляемые базовые элементы с окончательными полями, то можете использовать внедрение в конструкторе с помощью применения к конструктору аннотации `@Inject`. Затем вы можете применять любые аннотации к параметрам конструктора с целью квалификации базовых элементов для внедрения. (Разумеется, каждый параметр имеет тип, который может помочь квалифицировать компоненты для внедрения.) Компонент может иметь только один конструктор с определенными точками внедрения, но он может реализовать более одного конструктора. |
| |
| |
| [source,java] |
| ---- |
| |
| @Named |
| @RequestScoped |
| public class ItemProcessor { |
| |
| private final ItemDao itemDao; |
| |
| @Inject |
| public ItemProcessor(@Demo ItemDao itemDao) { |
| this.itemDao = itemDao; |
| } |
| } |
| ---- |
| |
| Вы также можете вызвать метод инициализации, который может быть передан базовому элементу для внедрения. |
| |
| |
| [source,java] |
| ---- |
| |
| @Named |
| @RequestScoped |
| public class ItemProcessor { |
| |
| private ItemDao itemDao; |
| |
| @Inject |
| public void setItemDao(@Demo ItemDao itemDao) { |
| this.itemDao = itemDao; |
| } |
| } |
| ---- |
| |
| Хотя в вышеприведенном случае для инициализации используется метод установки, вы можете создать любой метод и использовать его для инициализации любого количества базовых элементов при вызове метода. Вы также можете использовать несколько методов инициализации для одного базового элемента. |
| |
| |
| [source,java] |
| ---- |
| |
| @Inject |
| public void initBeans(@Demo ItemDao itemDao, @SomeQualifier SomeType someBean) { |
| this.itemDao = itemDao; |
| this.bean = someBean; |
| } |
| ---- |
| |
| Аналогичные правила применяются для сопоставления компонентов независимо от способа определения точки внедрения. CDI пытается найти лучшее соответствие на основе типа и квалификаторов и выдает сбой развертывания при наличии нескольких соответствующих компонентов или при отсутствии соответствующих компонентов для точки внедрения. |
| |
| link:/about/contact_form.html?to=3&subject=Feedback:%20Working%20with%20Injection%20and%20Qualifiers%20in%20CDI[+Отправить отзыв по этому учебному курсу+] |
| |
| |
| |
| [[seealso]] |
| == Дополнительные сведения |
| |
| Перейдите к следующему разделу этой серии для внедрения контекстов и зависимостей: |
| |
| * link:cdi-validate.html[+Применение аннотации @Alternative и аннотаций жизненного цикла+] |
| |
| Дополнительные сведения о CDI и Java EE приведены в следующих материалах. |
| |
| * link:cdi-intro.html[+Начало работы со внедрением контекстов и зависимостей и JSF 2.0+] |
| * link:javaee-gettingstarted.html[+Начало работы с приложениями Java EE+] |
| * link:http://blogs.oracle.com/enterprisetechtips/entry/using_cdi_and_dependency_injection[+Технические рекомендации по Java EE: использование CDI и внедрения зависимостей для Java в приложении JSF 2.0+] |
| * link:http://download.oracle.com/javaee/6/tutorial/doc/gjbnr.html[+Учебный курс по Java EE 6, часть V: внедрение контекстов и зависимостей для платформы Java EE+] |
| * link:http://jcp.org/en/jsr/detail?id=299[+JSR 299: спецификация внедрения контекстов и зависимостей+] |