cdi java что это

Apache NetBeans 12.5

Предоставлено Энди Гибсоном (Andy Gibson)

Внедрение контекстов и зависимостей

Введение в CDI и JSF 2.0

Внедрение контекстов и зависимостей (CDI), определяемое документом JSR-299, является неотъемлемой частью Java EE 6 и обеспечивает архитектуру, позволяющую компонентам Java EE (например, сервлетам, компонентам EJB и JavaBeans) существовать в жизненном цикле приложения с четко определенными контекстами. Кроме того, службы CDI позволяют компонентам Java EE (например, компонентам сеансов EJB и управляемым компонентам JavaServer Faces) внедряться и свободно взаимодействовать путем запуска и обработки событий.

Этот учебный курс основан на записи блога Энди Гибсона (Andy Gibson) Введение в JSF 2.0 и CDI в JEE 6. В нем рассматривается использование среды IDE для настройки веб-проекта Java с поддержкой JSF 2.0 и CDI. Затем описано связывание управляемых компонентов CDI со страницами Facelets и приводится краткий пример интеграции CDI и технологии EJB.

В NetBeans IDE обеспечена встроенная поддержка для внедрения контекстов и зависимостей, включая поддержку создания файла конфигурации CDI beans.xml при создании проекта, поддержку редактора и навигации для аннотаций, а также различных мастеров для создания часто используемых артефактов CD.

Для работы с этим учебным курсом требуется программное обеспечение и материалы, перечисленные ниже.

7.2, 7.3, 7.4, 8.0, пакет Java EE

Open Source Edition 3.x или 4.x

В комплект Java для IDE NetBeans также входит компонент GlassFish Server Open Source Edition, являющийся контейнером, совместимым с Java EE.

Создание веб-проекта Java с поддержкой CDI

В этом упражнении выполняется создание веб-проекта Java с поддержкой JSF 2.x и CDI.

Нажмите кнопку ‘Создать проект’ ( ) на главной панели инструментов IDE (Ctrl-Shift-N; ⌘-Shift-N в Mac).

В мастере создания проекта выберите категорию Java Web и команду «Веб-приложение». Нажмите кнопку «Далее».

Введите cdiDemo в качестве имени проекта и укажите местоположение проекта. Нажмите кнопку «Далее».

Выберите GlassFish в качестве сервера.

В качестве версии Java EE выберите Java EE 6 или Java EE 7 Web.

От выбранной версии Java EE зависит, какая версия CDI будет поддерживаться в приложении. Следует помнить, что между версиями CDI 1.0 и CDI 1.1 существует ряд различий.

Если в качестве версии Java EE выбрана Java EE 6 Web, убедитесь, что выбран параметр «Разрешить внедрение контекстов и зависимостей». При выборе параметра «Включить внедрение контекстов и зависимостей» создается файл beans.xml в папке проекта WEB-INF при создании шаблона проекта. Файл beans.xml используется CDI для указания серверу, совместимому с Java EE, что проект является модулем, содержащим компоненты CDI. Java EE 6 Web поддерживает CDI 1.0, и в создаваемом файле beans.xml будет указана версия CDI 1.0.

Подробные сведения о типах архивов CDI см. в разделе Упаковка приложений CDI в руководстве по Java EE 7.

Нажмите кнопку «Далее».

На панели «Платформы» выберите параметр JavaServer Faces.

Перейдите на вкладку «Настройка» и убедитесь, что в качестве предпочтительного языка страницы выбран «Facelets». Нажмите кнопку «Завершить».

Доступ к Beans из языка выражений JSF

В этом упражнении демонстрируется способ связи компонентов, управляемых CDI, со страницами Facelets с помощью синтаксиса EL.

В окне «Проекты» щелкните правой кнопкой узел «Исходные файлы» и выберите команду «Создать» > «Класс Java».

В мастере создания класса Java введите имя класса MessageServerBean и введите exercise1 в поле «Пакет». Новый пакет будет создан после завершения работы мастера. Нажмите «Готово».

Создаются новый пакет и класс, после чего класс открывается в редакторе.

Добавьте к классу аннотации @Named и @Dependent и создайте одиночный метод для возврата строки.

Во время добавления аннотаций @Dependent и @Named нажмите сочетание клавиш Ctrl-Пробел, чтобы включить в редакторе поддержку автозавершения кода и документации Javadoc. Если применить аннотацию с помощью функций автозавершения кода редактора (например, выбрав подходящую аннотацию и нажав ENTER), в файл автоматически добавляется оператор `импорта `. Во всплывающем окне Javadoc также можно нажать кнопку ‘Показывать документацию во внешнем веб-браузере’ ( ) для отображения полноразмерного Javadoc в отдельном окне.

Аннотация @Dependent определяет область действия управляемого компонента bean. В архиве неявного компонента bean управляемый компонент bean доступен только для обнаружения и может управляться контейнером, только если указана область действия. В данном упражнении приложение будет упаковано как архив неявного компонента bean (при условии, что в качестве версии проекта выбрана Java EE 7 и не создан файл beans.xml ). Подробные сведения об области действия управляемых компонентов bean см. в разделе Настройка управляемых компонентов bean с помощью аннотаций учебного курса по Java EE 7.

Сохраните файл (сочетание клавиш Ctrl-S; ⌘-S в Mac). После добавления аннотации @Named класс MessageServerBean стал _ управляемым компонентом _, в соответствии с определением CDI.

Для отображения подсказок автозавершения кода можно нажать сочетание клавиш CTRL+ПРОБЕЛ внутри выражения EL. Списки автозавершения редактора содержат управляемые компоненты и их свойства. Поскольку аннотация @Named преобразует класс MessageServerBean в управляемый компонент, он становится доступным в синтаксисе EL, как если бы он был управляемым компонентом JSF.#

Вернитесь к компоненту сообщения и измените сообщение на другое (например, «Hello Weld!»). Сохраните файл (Ctrl-S; ⌘-S в Mac), затем обновите браузер. Автоматически отображается новое сообщение. Это происходит благодаря возможности «Развертывание при сохранении» среды IDE, все сохраненные изменения вызывают компиляцию и повторное развертывание на сервере.

В третьей строке на этой странице видно, что имя класса – exercise1.MessageServerBean Обратите внимание, что компонент представляет собой объект POJO (Plain Old Java Object, простой старый объект Java). Несмотря на использование Java EE, при разработке отсутствует комплексная иерархия классов, связанная уровнями транзакций, перехватами и другие сложные особенности.

Читайте также:  что делать если джунгарика укусил кот

Порядок действий

Переход к EJB

Благодаря EJB 3.1 и использованию стека Java EE можно с небольшими изменениями легко развертывать компонент в качестве EJB.

Откройте MessageServerBean и добавьте аннотацию javax.ejb.Stateless на уровне класса, затем замените строку на «Hello EJB!».

Сохраните файл (Ctrl-S; ⌘-S в Mac), затем перейдите в браузер и обновите. Отображается приблизительно следующее:

Поразительно, POJO превратился в полнофункциональный EJB с помощью всего одной аннотации. После сохранения изменений и обновления страницы были отображены изменения. Для этого не потребовалось проводить комплексную настройку проекта, создавать локальные интерфейсы или сложные дескрипторы развертывания.

Различные типы EJB

Дополнительные сведения

В следующей части рассматривается внедрение CDI и приводятся подробные сведения об использовании CDI для управления зависимостями в среде Java EE.

Дополнительные сведения о CDI и JSF 2.0 приведены в следующих материалах.

Источник

Внедрение зависимостей в CDI. Часть 1

После статьи о том, как начать работу с CDI в вашем окружении и нескольких советов о том, как интегрировать CDI в существующее Java EE 6 приложение, я хочу поговорить о внедрении зависимостей. Да, о простом внедрении или о том, как провести внедрение одного бина в другой. Из этой серии трех статей (Часть 2, Часть 3) вы увидите, что есть множество различных способов: давайте начнем с самого простого — обыкновенного внедрения.

Внедрение по умолчанию

Самый простой способ внедрения… простой. У вас есть что-то, и вы что-то внедряете в это. Почему я использую слово что-то? Потому что до Java EE 5 вы могли внедрять только ресурсы (EntityManager, Datasource, JMS фабрики. ) в определенные компоненты (EJB и сервлеты). С CDI, вы можете внедрять практически что угодно во что угодно.

Для этой статьи я использовал следующее программное обеспечение:

Для иллюстрации внедрения я буду использовать тот же пример, что и в предыдущих статьях и в своей книге Java EE 6 (этот же пример Antonio использует и в книге Beginning Java EE 7 [перевод] — прим. пер.).

На диаграмме классов показаны следующие компоненты:

ItemServlet и ItemRestService очень похожи, так как в оба внедряются ссылки на ItemEJB и IsbnGenerator :

IsbnGenerator — это самый обычный POJO. Он ни от кого не наследуется и никак не проаннотирован:

Во всех этих случаях есть только одна реализация на выбор (есть только один ItemEJB и один IsbnGenerator ). Если у вас только одна реализацию, CDI сможет её внедрить. Далее мы поговорим о внедрении по умолчанию.

мог бы быть написан вот так:

В этой статье я использую термин бин, но если быть более точным, я должен говорить управляемый бин (например бин, управляемый CDI). ManagedBeans были введены в Java EE 6.

Неоднозначные внедрения и спецификаторы

В данной статье я использую внедрение через поле (атрибут) класса, но с CDI вы можете также использовать внедрение через сеттеры или конструкторы.

Это означает, что нужно убрать неоднозначность и указать CDI, какой бин и где должен внедряться. Если вы раньше использовали Spring, то первое, что придёт вам на ум, это «давайте использовать beans.xml«. Но, как рассказывается в этом посте, «beans.xml не тот XML, где определяются бины«. С CDI вы должны использовать спецификаторы (аннотации).

Есть три встроенных в CDI спецификатора:

Как вы видите, я только что очень просто определил два спецификатора. Как я теперь могу их использовать? Давайте посмотрим на диаграмму:

Вам не нужна внешняя конфигурация. Вот почему CDI предписывает использовать строгую типизацию. Вы можете переименовывать ваши реализации как захотите, точки внедрения при этом не будут меняться (это слабая связность). Обратите также внимание на то, что бин может быть объявлен несколькими спецификаторами. Как вы можете видеть, CDI — это элегантный способ иметь типобезопасное внедрение зависимостей. Но если вы начинаете создавать аннотации каждый раз, когда вам нужно что-то внедрить, в конечном итоге ваш код будет трудночитаемым. В этом случае вам помогут перечисления.

Спецификаторы с перечислениями

Каждый раз, когда вам необходимо выбирать между реализациями, вы создаете аннотацию. Тогда, если вам нужен дополнительный генератор 2-значных номеров или генератор 10-значных номеров, вы создаете всё больше и больше аннотаций. Похоже, что мы переходим от XML ада к аду аннотаций! Один из способов избежать их размножения — это использовать перечисления следующим образом:

Заключение

Я не знаю как вы, но я люблю CDI. Мне очень нравится, как CDI типобезопасно связывает бины обычной Java и без XML. Да, я признаю, что не всё так красиво. Первое, что я вижу, — это разрастание числа аннотаций в вашем коде. Благодаря перечислениям это можно ограничинить. Второе — это поддержка в IDE. Ваша IDE должна знать, что:

В следующей статье я рассмотрю различные точки внедрения.

Исходный код

Скачайте код и расскажите, что вы о нем думаете.

Источник

Dependency injection в Java EE 6

В рамках JSR-299 “Contexts and Dependency Injection for the Java EE platform” (ранее WebBeans) была разработана спецификация описывающая реализацию паттерна внедрения зависимости, включенная в состав Java EE 6. Эталонной реализацией является фреймворк Weld, о котором и пойдет речь в данной статье.

К сожалению в сети не так много русскоязычной информации о нем. Скорее всего это связано с тем, что Spring IOC является синонимом dependency injection в Java Enterprise приложениях. Есть конечно еще Google Guice, но он тоже не так популярен.

Читайте также:  с каким сервером компьютерной телефонии интегрировано по trassir

В статье хотелось бы рассказать об основных преимуществах и недостатках Weld.

Немного теории

В начале стоит упомянуть про JSR-330 “Dependency Injection for Java” спецификацию, разработанную инженерами из SpringSource и Google, определяющую базовые механизмы для реализации DI в Java приложениях. Как и Spring и Guice, Weld использует аннотации предусмотренные данной спецификацией.

Weld может работать не только с Java EE приложениями, но и с обычным окружением Java SE. Естественно есть поддержка Tomcat, Jetty; в официальной документации описаны подробные инструкции по настройке.

В Contexts and Dependency Injection (CDI) невозможно инъектировать бин через его имя в виде строки, как это например делается в Spring через Qualifier. Вместо этого используется шаблон qualifier annotations (о котором ниже). С точки зрения создателей CDI, это более typesafe подход, позволяющий избежать некоторых ошибок и обеспечивающий гибкость DI.

Для того, чтобы задействовать CDI нужно создать файл beans.xml в директории WEB-INF для веб-приложения (или в META-INF для Java SE):

@ConversationScoped представляет собой определенный промежуток времени взаимодействия пользователя с конкретной вкладкой в браузере. Поэтому он чем-то похож на жизненный цикл сессии, но важное отличие в том, что старт “сессии” задается вручную. Для этого объявлен интерфейс javax.enterprise.context.Conversation, который определяет методы start(), end(), а также setTimeout(long), для закрытия сессии по истечении времени.

Конечно же, есть и Singleton, который находится в пакете javax.inject, т.к. является частью спецификации JSR-330. В реализации CDI данного скоупа есть одна особенность: в процессе инъекции клиент получает ссылку на реальный объект созданный контейнером, а не proxy. В результате чего могут быть проблемы неоднозначности данных, если состояние синглтона будет меняться, а использующие его бины, например, были или будут сериализованы.

Для создания своего скоупа нужно написать аннотацию и отметить ее @ScopeType, а также реализовать интерфейс javax.enterprise.context.spi.Context.

Небольшая путаница может возникнуть с тем, что в пакете javax.faces.bean также находятся аннотации для управления скоупом managed бинов JSF. Связано это с тем, что в JSF приложениях использование CDI не обязательно: действительно, ведь можно обойтись стандартными инъекциями с помощью @EJB, @PersistenceContext и т.п. Однако, если мы хотим использовать продвинутые штуки из DI, удобней применять аннотации из JSR-299 и 330.

Примерчик

Допустим есть сервис проверяющий логин и пароль пользователя.

Напишем его реализацию:

Теперь добавим контроллер, который будет использовать сервис логина:

Как видно из примера, в этом случае для инъекции с помощью Weld необходимо добавить аннотацию Inject в нужном поле: контейнер найдет все возможные реализации интерфейса, выберет подходящую и создаст объект привязанный к скоупу контроллера. Естественно поддерживаются инъекции в метод и конструктор. В примере также используется аннотация Named, она служит для того, чтобы к бину можно было обращаться в EL по имени.

В процессе разработки нам бы хотелось иметь свою реализацию сервиса, примерно такого содержания:

Теперь после редеплоя приложения в консоли возникнет ошибка:

Если в точке инъекции подходят несколько реализаций, то Weld бросает исключение. Разработчики CDI предусмотрели разрешение такой проблемы. Для этого отметим StubLoginService аннотацией Alternative:

Теперь данная реализация недоступна для инъекций и после редеплоя ошибка не возникнет, однако сейчас Weld делает не совсем то, что нам нужно. Добавим следующее в beans.xml:

Таким образом мы подменили реализацию при старте приложения. Чтобы вернуть рабочую версию достаточно закомментировать строчку в файле настройке бинов.

Как это обычно бывает, обновили спецификацию и теперь сервис должен проверять пароль по хешу с использованием MD5 алгоритма. Добавим еще одну реализацию:

Теперь нужно сообщить Weld, что в точке инъекции необходимо подставить именно Md5LoginService. Для этого воспользуемся qualifier annotations. Сама идея очень проста: когда контейнер решает какую именно реализацию нужно внедрить, он проверяет аннотации в точке инъекции и аннотации у возможных реализаций. Проверяемые аннотации называются спецификаторами (qualifier). Спецификатор это обычная java аннотация, которая дополнительно аннотирована javax.inject.Qualifier:

Теперь в контроллере проаннатируем поле в которое будет совершена подстановка, а также реализацию Md5LoginService:

Теперь Weld подставит нужную реализацию. Конечно возникает вопрос: каждый раз писать новую аннотацию?! В большинстве случаев так и придется сделать, но эта плата за typesafe. К тому же аннотации можно агрегировать, например так:

Более того, чтобы не создавать большое количество одинаковых аннотаций, можно расширять аннотации полями и Weld учтет это:

Т.е. для рассматриваемого примера мы добавили новое поле c типом перечисления, указывающий какой именно это алгоритм хеширования. Пусть и пришлось написать новую аннотацию и перечисление, зато теперь практически невозможно ошибиться с выбором нужной реализации, к тому же увеличилась читабельность кода. Также нужно всегда помнить, что если реализация не имеет спецификатора, то он добавляется по умолчанию javax.enterprise.inject.Default.

Правда после проделанных манипуляций StubLoginService перестал подставляться в поле. Это связано с тем, что у него нет спецификатора Hash, поэтому Weld даже не рассматривает его как возможную реализацию интерфейса. Для решения этой проблемы есть одна хитрость: аннотация @Specializes, которая заменяет реализацию другого бина. Чтобы указать Weld какую именно реализацию нужно заменить, нужно ее просто расширить:

Представим, что у нас появились новые требования: при попытке входа пользователя в систему, нужно попытаться проверить пароль всеми возможными алгоритмами реализованными в системе. Т.е. нам нужно перебрать все реализации интерфейса. В Spring такая задача решается через подстановку в коллекцию обобщенную по нужному интерфейсу. В Weld для этого можно использовать интерфейс javax.enterprise.inject.Instance и встроенный спецификатор Any. Пока отключим альтернативные реализации и посмотрим, что получится:

Читайте также:  что делает тв тюнер

Аннотация Any говорит о том, что нам все равно какие спецификаторы могут быть у реализаций. Интерфейс Instance реализует Iterable, поэтому с ним можно делать такие красивые штуки через foreach. Вообще этот интерфейс предназначен не только для этого. Он содержит перегруженный метод select(), который позволяют в runtime выбирать нужную реализацию. В качестве параметров он принимает экземпляры аннотаций. В целом сейчас это реализовано несколько “необычно”, поскольку приходится создавать анонимные классы (или создавать отдельно, только для того чтобы использовать в одном месте). Частично это решается абстрактным классом AnnotationLiteral от которого можно расшириться и обобщить по нужной аннотации. Помимо этого в Instance есть специальные методы isUnsatisfied и isAmbiguous, с помощью которых можно в runtime проверить есть ли подходящая реализация и только потом получить ее экземпляр через метод get(). Выглядит это примерно так:

Понятно, что в данном случае можно было пройтись циклом по loginServiceInstance, как это сделали в примере выше, и найти нужную реализацию по getClass().equals(), но тогда при изменении реализаций пришлось править код и в этом месте тоже. Weld представляет более гибкий и безопасный подход, пусть немного добавляя новых абстракций для изучения.

Как уже было отмечено выше, Weld при выборе нужной реализации руководствуется и типом и спецификатором. Но в некоторых случаях, например со сложной иерархией наследования, мы можем указать тип реализации в ручную, используя аннотацию @Typed.

Это все конечно хорошо, но что делать когда нам нужно создать экземпляр класса каким-то хитрым способом? Опять же Spring в xml контексте предлагает богатый набор тегов для инициализации свойств у объектов, создания списков, мап и т.д. У Weld для этого есть всего одна аннотация @Produces, которой отмечаются методы и поля генерирующие объекты (в том числе и скалярных типов). Перепишем наш предыдущий пример:

Теперь укажем через спецификатор откуда хотим получить реализацию:

Вот собственно и все. Источником может быть и обычное поле. Правила подстановки теже самые. Более того в метод buildLoginService можно также инъектировать бины:

Как видите модификатор доступа никак не влияет. Скоуп объектов генерируемых buildLoginService не привязан к скоупу бина, в котором он объявлен, поэтому в данном случае он будет Dependent. Чтобы это изменить достаточно добавить аннотацию к методу, например так:

Помимо этого можно вручную освобождать ресурсы генерируемые с помощью @Produces. Для этого, Вы не поверите, есть другая аннотация @Disposed, которая работает примерно так:

Когда жизненный цикл объекта подходит к концу, Weld ищет методы удовлетворяющие типу и спецификатору метода генаратора, а также помеченные @Disposed и вызывает его.

Заключение

Мы рассмотрели далеко не все возможности JSR-299. Помимо этого есть ряд дополнительных спецификаторов, механизмы управления жизненным циклом бинов внутри контейнера (interceptors, decorators), стереотипы, событийная модель, с помощью которой удобно организовывать сложную бизнес логику и еще много-много приятных мелочей.

В данной статье не хотелось противопоставлять Weld другим dependency injection фреймворкам, о которых говорилось в начале. Weld самодостаточен и обладает интересной реализацией, достойной внимания Java Enterprise разработчиков.

Источник

Введение в контексты и внедрение зависимостей (CDI)

Содержание

CDI (контексты и внедрение зависимостей) — это спецификация внедрения зависимостей (DI), связанная с Java EE 6 и выше. Он реализует основанную на аннотациях структуру DI, облегчая полную автоматизацию управления зависимостями и позволяя разработчикам сосредоточиться на кодировании, а не на работе с DI во всех его различных направлениях.

С учетом сказанного в этом руководстве я предоставлю вам практическое руководство по использованию CDI / Weld в Java SE.

Простое введение зависимости с помощью CDI

Создание точки впрыска

Рассмотрим следующий пример, который является частью простого приложения, которое обрабатывает данную строку несколькими основными способами:

API для обработки строк настолько прост, что не заслуживает дальнейшего анализа. Итак, вот соответствующие реализации:

К этому моменту мы создали три простых реализации, функциональность которых сводится к нижнему регистру, верхнему регистру и обращению заданной строки.

Теперь предположим, что мы хотим внедрить во время выполнения экземпляр этих классов в объект клиента, чтобы обработать строку, введенную в консоли. В таком случае сначала нам нужно определить класс, похожий на этот:

Bootstrapping Weld

Ну, не все так просто. Сначала нам нужно скачать артефакт Weld — вот он для Maven:

Все должно работать как положено. Или не должно?

@Default реализации с @Default и @Alternative

После изменения классов запустите приложение еще раз. Вам будет предложено ввести строку в консоли, и, как и следовало ожидать, вывод будет выглядеть красиво в верхнем регистре! Посмотрите, насколько легко использовать CDI / Weld и насколько они мощны, даже если вы делаете что-то столь же тривиальное, как разбор строки?

Но есть еще много чего, чтобы покрыть. Даже когда аннотации @Default и @Alternative делают довольно приличную работу, когда дело доходит до инструктирования CDI о том, какие реализации нужно внедрить во время выполнения в объект клиента, их функциональность довольно ограничена, так как большинство IDE просто не даст вам ни единой подсказки о том, что вы пытаетесь ввести и где.

Чтобы решить эту проблему, CDI предоставляет несколько более интуитивно понятных механизмов для достижения того же результата, включая аннотацию @Named и пользовательские квалификаторы.

Представляем аннотацию @Named

Источник

Сказочный портал