// 
//     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,Дополнительные сведения>>


. link:cdi-validate.html[+Применение аннотации @Alternative и аннотаций жизненного цикла+]


. link:cdi-events.html[+Обработка событий в CDI+]

Внедрение контекстов и зависимостей (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."]



. Нажмите кнопку "Завершить". Выполняется создание нового класса и пакета, и класс `Item` открывается в редакторе.


. Создайте свойства `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);
    }*
}
----


. Добавьте методы получения и установки к классу. Для этого убедитесь, что курсор размещен в определении класса (т.е. между фигурными скобками класса), затем щелкните в редакторе правой кнопкой мыши и выберите пункт "Вставить код" (ALT+INSERT; CTRL+I на компьютерах Mac). Выберите методы получения и установки. 

image::images/insert-code.png[title="Создайте методы получения и установки с помощью всплывающего окна 'Вставить код'"]



. Установите флажок `Item` (при этом выбираются все свойства, содержащиеся в классе). 

image::images/generate-getters-setters.png[title="Установите флажок для класса для выбора всех свойств, содержащихся в классе"]



. Нажмите кнопку "Создать". Для класса создаются методы получения и установки.

[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);
    }
}
----


. Создайте конструктор, который принимает оба аргумента `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;

    ...
----


. Создайте интерфейс `ItemDao` для определения способа получения списка объектов `Item`. В этом тестовом приложении мы допускаем использование нескольких реализаций, следовательно, создаем код для интерфейсов.

Щелкните 'Создать файл' ( image:images/new-file-btn.png[] ) или нажмите сочетание клавиш CTRL+N (⌘-N on Mac) для открытия мастера создания файлов.



. Выберите категорию Java, а затем команду "Интерфейс Java". Нажмите кнопку "Далее".


. Введите *ItemDao* в качестве имени класса, затем укажите *exercise2* в качестве пакета.


. Нажмите кнопку "Завершить". Интерфейс будет создан и открыт в редакторе.


. Добавьте метод с именем `fetchItems()`, который возвращает элемент `List` объектов `Item`.

[source,java]
----

public interface ItemDao {

    *List<Item> fetchItems();*

}
----
Используйте подсказку редактора, чтобы добавить оператор импорта для `java.util.List`.


. Создайте класс `ItemProcessor`. Это главный класс для внедрения базовых элементов и выполнения процесса. базовый элемент.

Щелкните 'Создать файл' ( image:images/new-file-btn.png[] ) или нажмите сочетание клавиш CTRL+N (⌘-N on Mac) для открытия мастера создания файлов.



. Выберите категорию Java, а затем выберите класс Java. Нажмите кнопку "Далее".


. Введите *ItemProcessor* в качестве имени класса, затем укажите *exercise2* в качестве пакета. Нажмите кнопку "Завершить".

В редакторе будет создан и открыт новый класс.



. Измените класс следующим образом:

[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);
        }
    }
}
----


. Исправьте операторы импорта. Либо щелкните правой кнопкой мыши в редакторе и выберите 'Исправить выражения импорта' или нажмите Ctrl-Shift-I (⌘-Shift-I в Mac). 

image::images/fix-imports.png[title="Щелкните в редакторе правой кнопкой мыши и выберите 'Исправить операторы импорта' для добавления операторов импорта к классу"]



. Нажмите кнопку "ОК". Операторы импорта требуются для следующих классов:
* `java.util.List`
* `javax.inject.Named`
* `javax.enterprise.context.RequestScoped`


. Начните с простого DAO, который только создает список элементов и возвращает фиксированный список элементов. 

В окне "Проекты" щелкните правой кнопкой мыши узел пакета `exercise2` и выберите "Создать > Класс Java". В мастере создания класса Java присвойте классу имя `DefaultItemDao`. Нажмите кнопку "Завершить". 

image::images/java-class-wizard2.png[title="Создайте новый класс Java с помощью мастера классов Java"]



. Необходимо, чтобы в редакторе элемент `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`.


. Перейдите к классу `ItemProcessor` (нажмите сочетание клавиш CTRL+TAB). Чтобы внедрить `DefaultItemDao` в `ItemProcessor` добавляется аннотация `javax.inject.Inject` к полю `ItemDao` для указания того, что это поле является точкой внедрения.

[source,java]
----

*import javax.inject.Inject;*
...

@Named
@RequestScoped
public class ItemProcessor {

    *@Inject*
    private ItemDao itemDao;

    ...
}
----

TIP: Используйте поддержку автозавершения кода редактора для добавления аннотации `@Inject` и оператора импорта к классу. Например, введите `@Inj`, а затем нажмите CTRL+ПРОБЕЛ.#



. Наконец, необходим способ для вызова метода `execute()` в `ItemProcessor`. Это можно выполнить в среде SE, но сейчас мы сделаем это на странице JSF. Создайте новую страницу с именем `process.xhtml`, которая содержит кнопку для вызова метода `execute()`. 

Щелкните 'Создать файл' ( image:images/new-file-btn.png[] ) или нажмите сочетание клавиш CTRL+N (⌘-N on Mac) для открытия мастера создания файлов.


. Выберите категорию JavaServer Faces, затем выберите страницу JSF. Нажмите кнопку "Далее".


. Введите *process* в качестве имени файла, затем нажмите кнопку "Готово". 

image::images/new-jsf-page.png[title="Создайте новую страницу Facelets с помощью мастера файлов JSF"]



. В новом файле `process.xhtml` добавьте кнопку, которая привязана к методу `ItemProcessor.execute()`. При использовании языка выражений имя по умолчанию для управляемого компонента является таким же, как имя класса, но первая буква в нижнем регистре (т.е. `itemProcessor`).

[source,xml]
----

<h:body>
    *<h:form>
        <h:commandButton action="#{itemProcessor.execute}" value="Execute"/>
    </h:form>*
</h:body>
----


. Перед выполнением проекта установите файл `process.xhtml` в качестве новой страницы приветствия в дескрипторе развертывания веб-приложения. 

Используйте диалоговое окно среды IDE "Переход к файлу" для быстрого открытия файла `web.xml`. В основном меню среды IDE выберите "Переход > Перейти к файлу" (ALT+SHIFT+O; CTRL+SHIFT+O на компьютерах Mac), а затем введите `web`. 

image::images/go-to-file.png[title="С помощью диалогового окна &quot;Переход к файлу&quot; быстро найдите файл проекта"]



. Нажмите кнопку "ОК". В представлении XML для файла `web.xml` выполните следующие изменения.

[source,xml]
----

<welcome-file-list>
    <welcome-file>faces/*process.xhtml*</welcome-file>
</welcome-file-list>
----


. Нажмите кнопку 'Запустить проект' (image:images/run-project-btn.png[]) на главной панели инструментов IDE. Проект компилируется и развертывается на GlassFish, и файл `process.xhtml` открывается в браузере.


. Нажмите кнопку `Выполнить` на странице. Вернитесь в среду IDE и проверьте протокол сервера GlassFish. Журнал сервера отображается в окне вывода (Ctrl-4; ⌘-4 в Mac) на вкладке 'Сервер GlassFish'. При нажатии кнопки журнал выводит список элементов из реализации DAO по умолчанию. 

image::images/output-window.png[title="Проверьте журнал сервера в окне вывода IDE"] 

TIP: Щелкните правой кнопкой мыши окно вывода и выберите 'Очистить' (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`, не так ясно, какой базовый элемент необходимо внедрить.



. Для запуска проекта нажмите кнопку 'Запустить проект' ( image:images/run-project-btn.png[] ). Обратите внимание, что теперь развертывание проекта завершается сбоем.

Возможно, вам просто необходимо сохранить файл - IDE будет автоматически запускать проект, т.к. запуск при сохранении активирован по умолчанию.



. Проверьте журнал сервера в окне вывода (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.



. Щелкните 'Создать файл' ( image:images/new-file-btn.png[] ) или нажмите сочетание клавиш CTRL+N (⌘-N on Mac) для открытия мастера создания файлов.


. Выберите категорию "Внедрение контекстов и зависимостей", затем выберите "Тип "квалификатора". Нажмите кнопку "Далее".


. Введите *Demo* в качестве имени класса, затем укажите *exercise2* в качестве пакета.


. Нажмите кнопку "Завершить". Новый квалификатор `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 на уровне класса.


. Перейдите в редакторе к `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;
}
}
----

TIP: После ввода `@` нажмите CTRL+ПРОБЕЛ для вызова предложений автозавершения кода. Редактор распознает квалификатор `Demo` и выводит `@Demo` в качестве параметра списка для автозавершения кода.#



. Для запуска проекта нажмите кнопку 'Запустить проект' ( image:images/run-project-btn.png[] ). Сборка и развертывание проекта выполняются без ошибок.

NOTE:  Для этого изменения может потребоваться явно запустить проект для повторного развертывания приложения вместо развертывания изменений с приращением.



. В браузере нажмите кнопку `Выполнить`, затем вернитесь в среду IDE и проверьте протокол сервера в окне вывода. На экран будет выведено следующее.

[source,java]
----

INFO: Found item exercise2.Item@1ef62a93 [Value=99, Limit=9]
----

Выводится позиция из класса `AnotherItemDao`. Следует помнить о том, что аннотирована реализация `DefaultItemDao`, но не точка внедрения в `ItemProcessor`. За счет добавления квалификатора `@Demo` к реализации DAO по умолчанию другая реализация стала более походящей для точки внедрения, поскольку она соответствует типу и квалификатору. `DefaultItemDao` имеет в настоящий момент квалификатор `Demo`, который расположен не в точке внедрения, что делает его менее подходящим.

Затем вы добавите аннотацию `@Demo` к точке внедрения в`ItemProcessor`.



. Перейдите в редакторе к `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);
    }
}
}
----


. В браузере нажмите кнопку `Выполнить`, затем вернитесь в среду 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: спецификация внедрения контекстов и зависимостей+]
