| // |
| // 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. |
| // |
| |
| = Применение аннотации @Alternative и аннотаций жизненного цикла |
| :jbake-type: tutorial |
| :jbake-tags: tutorials |
| :jbake-status: published |
| :icons: font |
| :syntax: true |
| :source-highlighter: pygments |
| :toc: left |
| :toc-title: |
| :description: Применение аннотации @Alternative и аннотаций жизненного цикла - Apache NetBeans |
| :keywords: Apache NetBeans, Tutorials, Применение аннотации @Alternative и аннотаций жизненного цикла |
| |
| _Предоставлено Энди Гибсоном (Andy Gibson)_ |
| |
| == Внедрение контекстов и зависимостей |
| |
| 1. link:cdi-intro.html[+Введение в CDI и JSF 2.0+] |
| 2. link:cdi-inject.html[+Работа с внедрением и квалификаторами в CDI+] |
| 3. *Применение аннотации @Alternative и аннотаций жизненного цикла* |
| * <<alternative,Обработка нескольких развертываний>> |
| * <<lifecycle,Применение аннотаций жизненного цикла к управляемым компонентам>> |
| * <<seealso,Дополнительные сведения>> |
| |
| [start=4] |
| . 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. Внедрение+]. В нем рассматривается использование аннотации `@Alternative` для настройки приложения для различных развертываний, а также показано, как использовать аннотации жизненного цикла управляемых компонентов, например, `@PostConstruct` и `@PreDestroy` для совмещения внедрения CDI с функциональными возможностями link:http://jcp.org/en/jsr/detail?id=316[+спецификации управляемых компонентов Java EE 6+] |
| |
| В 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%252FcdiDemo2.zip[+cdiDemo2.zip+] |неприменимо |
| |=== |
| |
| |
| [NOTE] |
| ==== |
| * В комплект Java для IDE NetBeans также входит компонент GlassFish Server Open Source Edition, являющийся контейнером, совместимым с Java EE. |
| * Пример проекта к этому учебному курсу можно загрузить здесь: link:https://netbeans.org/projects/samples/downloads/download/Samples%252FJavaEE%252FcdiDemo3.zip[+cdiDemo3.zip+] |
| ==== |
| |
| |
| |
| [[alternative]] |
| == Обработка нескольких развертываний |
| |
| CDI предлагает использовать аннотацию `@Alternative`, которая позволяет пакетировать несколько компонентов, соответствующих одной точке внедрения, без неоднозначностей. Другими словами, аннотация `@Alternative` может применяться к двум или нескольким компонентам, а затем, в зависимости от развертывания, в файле настройки CDI `beans.xml` указывается компонент для использования. |
| |
| Для наглядности рассмотрим следующий случай. `ItemValidator` добавляется в главный класс `ItemProcessor`. `ItemValidator` имеет две реализации: `DefaultItemValidator` и `RelaxedItemValidator`. В соответствие с требованиями к развертыванию в большинстве случаев требуется использовать `DefaultItemValidator`, а `RelaxedItemValidator` — в одном конкретном развертывании. Для этого создаются аннотации к каждому компоненту, а затем указывается компонент, который используется для данного развертывания путем добавления записей в файл приложения `beans.xml` . |
| |
| image::images/cdi-diagram-alternative.png[title="Используйте внедрение CDI для свободного взаимодействия классов в используемом приложении"] |
| |
| 1. Начните работу с извлечения начального проекта из файла `cdiDemo2.zip` (см. выше <<requiredSoftware,таблицу необходимых ресурсов>>). Выберите File ("Файл") > Open Project ("Открыть проект") (Ctrl-Shift-O), затем выберите проект в его местоположении на компьютере. |
| 2. Щелкните правой кнопкой мыши узел проекта в окне "Проекты" и выберите команду "Свойства". |
| 3. Выберите категорию "Запуск" и убедитесь, что в списке "Сервер" выбран экземпляр GlassFish. |
| 4. Создайте интерфейс `ItemValidator`. |
| |
| Щелкните 'Создать файл' ( image:images/new-file-btn.png[] ) или нажмите сочетание клавиш CTRL+N (⌘-N on Mac) для открытия мастера создания файлов. |
| |
| [start=5] |
| . Выберите категорию Java, а затем команду "Интерфейс Java". Нажмите кнопку "Далее". |
| |
| [start=6] |
| . Введите имя класса в *ItemValidator* и пакет *exercise3*. |
| |
| [start=7] |
| . Нажмите кнопку "Завершить". Интерфейс будет создан и открыт в редакторе. |
| |
| [start=8] |
| . Добавьте метод `isValid()`, который принимает в качестве параметра объект `Item` и возвращает логическое значение `boolean`. |
| |
| [source,java] |
| ---- |
| |
| public interface ItemValidator { |
| *boolean isValid(Item item);* |
| } |
| ---- |
| С помощью подсказки редактора добавьте оператор импорта для `exercise2.Item`. |
| |
| [start=9] |
| . Расширьте класс `ItemProcessor` для добавления новой возможности. Откройте в редакторе `ItemProcessor` и внесите следующие изменения. |
| |
| [source,java] |
| ---- |
| |
| @Named |
| @RequestScoped |
| public class ItemProcessor { |
| |
| @Inject @Demo |
| private ItemDao itemDao; |
| |
| *@Inject |
| private ItemValidator itemValidator;* |
| |
| public void execute() { |
| List<Item> items = itemDao.fetchItems(); |
| for (Item item : items) { |
| System.out.println(*"Item = " + item + " valid = " + itemValidator.isValid(item)*); |
| } |
| } |
| } |
| ---- |
| |
| С помощью подсказки редактора добавьте оператор импорта для `exercise3.ItemValidator`. |
| |
| |
| [start=10] |
| . Создайте реализацию `ItemValidator` под названием `DefaultItemValidator`, которая просто сравнивает значение с предельным. |
| |
| В окне "Проекты" щелкните правой кнопкой пакет `exercise3` и выберите команду "Создать" > "Класс Java". Дайте классу имя *DefaultItemValidator* и нажмите кнопку "Готово". |
| |
| |
| [start=11] |
| . В элементе `DefaultItemValidator` реализуйте `ItemValidator` и переопределите метод `isValid()` следующим образом. |
| |
| [source,java] |
| ---- |
| |
| public class DefaultItemValidator *implements ItemValidator* { |
| |
| *@Override |
| public boolean isValid(Item item) { |
| return item.getValue() < item.getLimit(); |
| }* |
| } |
| ---- |
| |
| С помощью подсказки редактора добавьте оператор импорта для `exercise2.Item`. |
| |
| |
| [start=12] |
| . Нажмите кнопку 'Запустить проект' (image:images/run-project-btn.png[]) на главной панели инструментов IDE. Файл скомпилирован и развернут в GlassFish, и страница приветствия приложения (`process.xhtml`) отображается в веб-браузере. |
| |
| [start=13] |
| . Нажмите кнопку `Выполнить` на странице. Вернитесь в среду IDE и проверьте протокол сервера GlassFish. Журнал сервера отображается в окне вывода (Ctrl-4; ⌘-4 в Mac) на вкладке 'GlassFish'. В нем видно, что элементы проверяются и перечисляются только допустимые элементы, значение которых меньше предельного. |
| |
| [source,java] |
| ---- |
| |
| INFO: Item = exercise2.Item@e857ac [Value=34, Limit=7] valid = false |
| INFO: Item = exercise2.Item@63124f52 [Value=4, Limit=37] valid = true |
| INFO: Item = exercise2.Item@4715c34e [Value=24, Limit=19] valid = false |
| INFO: Item = exercise2.Item@65c95a57 [Value=89, Limit=32] valid = false |
| ---- |
| |
| image::images/output-window.png[title="Просмотрите журнал сервера в окне вывода"] |
| |
| |
| [start=14] |
| . Теперь рассмотрим случай, в котором вам необходимо выполнить развертывание в другом месте, менее жестком, считающим компонент недопустимым только в том случае, если его значение более чем в два раза превышает ограничение. Может потребоваться другой компонент для реализации интерфейса `ItemValidator` для данной логики. |
| |
| Создайте новую реализацию `ItemValidator` с именем `RelaxedItemValidator`. В окне "Проекты" щелкните правой кнопкой пакет `exercise3` и выберите команду "Создать" > "Класс Java". Дайте классу имя *RelaxedItemValidator* и нажмите кнопку "Готово". |
| |
| |
| [start=15] |
| . Сделайте `RelaxedItemValidator` реализацией `ItemValidator` и переопределите метод `isValid()` следующим образом. |
| |
| [source,java] |
| ---- |
| |
| public class RelaxedItemValidator *implements ItemValidator* { |
| |
| *@Override |
| public boolean isValid(Item item) { |
| return item.getValue() < (item.getLimit() * 2); |
| }* |
| } |
| ---- |
| |
| С помощью подсказки редактора добавьте оператор импорта для `exercise2.Item`. |
| |
| |
| [start=16] |
| . Для запуска проекта нажмите кнопку 'Запустить проект' ( image:images/run-project-btn.png[] ). Обратите внимание, что теперь развертывание проекта завершается сбоем. |
| |
| [start=17] |
| . Проверьте журнал сервера в окне вывода (Ctrl-4; ⌘-4 в Mac). В протоколе отображается сообщение об ошибке неоднозначной зависимости. Это происходит по причине того, что имеются два класса, реализующих один и тот же интерфейс. |
| |
| [source,java] |
| ---- |
| |
| org.glassfish.deployment.common.DeploymentException: Injection point has ambiguous dependencies. |
| Injection point: field exercise2.ItemProcessor.itemValidator; |
| Qualifiers: [@javax.enterprise.inject.Default()]; |
| Possible dependencies: [exercise3.RelaxedItemValidator, exercise3.DefaultItemValidator] |
| ---- |
| |
| Реализация Weld CDI не способна определить элемент, используемый для данной точки внедрения (`RelaxedItemValidator` или `DefaultItemValidator`). |
| |
| Как указано выше, единственное отличие связано с развертыванием. Для большинства развертываний можно использовать средство проверки по умолчанию, однако для одного развертывания может потребоваться использование "нежесткой" реализации. В CDI существует аннотация `@Alternative`, которая позволяет пакетировать несколько компонентов, соответствующих одной точке внедрения, без проблем неоднозначности, поскольку при этом используется компонент, указанный в файле `beans.xml` . Это позволяет развертывать в одном модуле обе реализации. При этом отличается только определение в файле `beans.xml` , которое уникально для каждой реализации. |
| |
| |
| [start=18] |
| . Добавьте аннотацию `@Alternative` и соответствующий оператор импорта в `RelaxedItemValidator` и `DefaultItemValidator`. |
| |
| Откройте в редакторе `RelaxedItemValidator` и внесите следующие изменения. |
| |
| [source,java] |
| ---- |
| |
| *import javax.enterprise.inject.Alternative;* |
| ... |
| |
| *@Alternative* |
| public class RelaxedItemValidator implements ItemValidator { |
| |
| public boolean isValid(Item item) { |
| return item.getValue() < (item.getLimit() * 2); |
| } |
| } |
| ---- |
| |
| Введите '`@Al`', затем нажмите CTRL+ПРОБЕЛ для вызова автозавершения кода. Поскольку возможен только один вариант, аннотация `@Alternative` завершается, а в начале файла автоматически добавляется соответствующий оператор импорта для `javax.enterprise.inject.Alternative`. Как правило, при нажатии CTRL+ПРОБЕЛ в аннотациях также вызывается всплывающая документация Javadoc. |
| |
| image::images/code-completion-alternative.png[title="Нажмите Ctrl-Space в аннотациях для вызова документации Javadoc"] |
| |
| Переключитесь к `DefaultItemValidator` (нажмите сочетание клавиш CTRL+TAB) и внесите следующее изменение. |
| |
| |
| [source,java] |
| ---- |
| |
| *import javax.enterprise.inject.Alternative;* |
| ... |
| |
| *@Alternative* |
| public class DefaultItemValidator implements ItemValidator { |
| |
| public boolean isValid(Item item) { |
| return item.getValue() < item.getLimit(); |
| } |
| } |
| ---- |
| |
| Выполняя развертывание приложения сейчас, вы получите ошибку "неудовлетворенная зависимость", так как два подходящих компонента были определены как альтернативные, но ни один из них не был активирован в файле `beans.xml` . |
| |
| |
| [start=19] |
| . С помощью диалогового окна "Переход к файлу" в среде IDE откройте файл `beans.xml` . Выберите пункт "Переход" > "Переход к файлу" в главном меню среды IDE (сочетание клавиш ALT+SHIFT+O; CTRL+SHIFT+O в Mac OS), затем введите `beans`. Нажмите кнопку "ОК". |
| |
| image::images/go-to-file.png[title="С помощью диалогового окна "Переход к файлу" быстро найдите файл проекта."] |
| |
| |
| [start=20] |
| . Внесите следующие изменения в файл `beans.xml` |
| |
| [source,xml] |
| ---- |
| |
| <beans xmlns="http://java.sun.com/xml/ns/javaee" |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> |
| |
| *<alternatives> |
| <class>exercise3.RelaxedItemValidator</class> |
| </alternatives>* |
| |
| </beans> |
| ---- |
| |
| Данная команда указывает CDI использовать `RelaxedItemValidator` для данного развертывания. Аннотация `@Alternative` может рассматриваться как способ отключения компонента, запрещения его внедрения и разрешения пакетирования реализации с другими компонентами. Добавление компонента в качестве альтернативы в файл `beans.xml` фактически снова разрешает компонент, делая его доступным для внедрения. Перемещение этого вида метаданных в файл `beans.xml` позволяет связать различные версии файла с различными развертываниями. |
| |
| |
| [start=21] |
| . Для запуска проекта нажмите кнопку 'Запустить проект' ( image:images/run-project-btn.png[] ). (В качестве альтернативы нажмите F6; fn-F6 в Mac) В браузере нажмите кнопку '`Выполнить`' на отображаемой странице. Переключите обратно в IDE и проверьте журнал сервера GlassFish, который отображается в окне вывода (Ctrl-4; ⌘-4 в Mac). |
| |
| [source,java] |
| ---- |
| |
| INFO: Item = exercise2.Item@672f0924 [Value=34, Limit=7] valid = false |
| INFO: Item = exercise2.Item@41014f68 [Value=4, Limit=37] valid = true |
| INFO: Item = exercise2.Item@3d04562f [Value=24, Limit=19] valid = true |
| INFO: Item = exercise2.Item@67b646f4 [Value=89, Limit=32] valid = false |
| ---- |
| |
| Используется реализация `RelaxedItemValidator`, а третий элемент отображается как верный, хотя значение (`24`) больше заданного предела (`19`). |
| |
| |
| |
| [[lifecycle]] |
| == Применение аннотаций жизненного цикла к управляемым компонентам |
| |
| В этом упражнении `ItemErrorHandler` будет добавлен в главный класс `ItemProcessor`. Для добавления выбран `FileErrorReporter`, поскольку он является единственной реализацией интерфейса `ItemErrorHandler`. Для настройки зависящих от жизненного цикла действий класса следует использовать аннотации `@PostConstruct` и `@PreDestroy` из спецификации управляемых компонентов (включенной в link:http://jcp.org/en/jsr/detail?id=316[+JSR 316: спецификация платформы Java, Enterprise Edition 6+]). |
| |
| image::images/cdi-diagram-lifecycle.png[title="Используйте внедрение CDI для свободного взаимодействия классов в используемом приложении"] |
| |
| После этого необходимо создать интерфейс `ItemErrorHandler` для обработки обнаруженных недопустимых элементов. |
| |
| 1. В окне "Проекты" щелкните правой кнопкой пакет `exercise3` и выберите команду "Создать" > "Интерфейс Java". |
| 2. В мастере интерфейсов Java введите имя класса *ItemErrorHandler* и имя пакета *exercise3*. Нажмите кнопку "Завершить". |
| |
| Интерфейс будет создан и открыт в редакторе. |
| |
| |
| [start=3] |
| . Добавьте метод `handleItem()`, принимающий параметр типа `Item`. |
| |
| [source,java] |
| ---- |
| |
| public interface ItemErrorHandler { |
| *void handleItem(Item item);* |
| } |
| ---- |
| |
| С помощью подсказки редактора добавьте оператор импорта для `exercise2.Item`. |
| |
| |
| [start=4] |
| . Выполните реализацию `ItemErrorHandler` с фиктивным обработчиком `FileErrorReporter`, сохраняющим данные элемента в файл. |
| |
| В окне "Проекты" щелкните правой кнопкой пакет `exercise3` и выберите команду "Создать" > "Класс Java". Присвойте классу имя *FileErrorReporter* и нажмите кнопку "Готово". |
| |
| |
| [start=5] |
| . Сделайте `FileErrorReporter` реализацией `ItemErrorHandler` и переопределите метод `handleItem()` следующим образом. |
| |
| [source,java] |
| ---- |
| |
| public class FileErrorReporter *implements ItemErrorHandler* { |
| |
| *@Override |
| public void handleItem(Item item) { |
| System.out.println("Saving " + item + " to file"); |
| }* |
| } |
| ---- |
| |
| С помощью подсказки редактора добавьте оператор импорта для `exercise2.Item`. |
| |
| Вам нужно открыть файл до начала обработки элементов, оставить его открытым в течение процесса добавления содержимого в данный файл, а затем закрыть его по завершении процесса. Можно вручную добавить методы `initProcess()` и `finishProcess()` к компоненту средства сообщения об ошибке, но в этом случае вы не сможете выполнить кодирование интерфейса, так как вызывающей стороне будет необходимо знать данные специфичные для класса методы. Можно добавить те же методы к интерфейсу `ItemErrorReporter`, но в этом случае потребуется выполнить ненужное внедрение данных методов в каждый класс, реализующий данный интерфейс. Вместо этого можно использовать несколько аннотаций жизненного цикла из спецификации управляемых компонентов (входящей в link:http://jcp.org/en/jsr/detail?id=316[+JSR 316: спецификация платформы Java, Enterprise Edition 6+]) для вызова методов в компоненте в конкретных точках жизненного цикла компонента. Метод с аннотацией `@PostConstruct` вызывается после создания компонента и учета всех его зависимостей. Метод с аннотацией `@PreDestroy` аналогичным образом вызывается непосредственно перед удалением компонента контейнером. |
| |
| |
| [start=6] |
| . Добавьте следующие методы `init()` и `release()` с аннотациями `@PostConstruct` и `@PreDestroy`. |
| |
| [source,java] |
| ---- |
| |
| public class FileErrorReporter implements ItemErrorHandler { |
| |
| *@PostConstruct |
| public void init() { |
| System.out.println("Creating file error reporter"); |
| } |
| |
| @PreDestroy |
| public void release() { |
| System.out.println("Closing file error reporter"); |
| }* |
| |
| @Override |
| public void handleItem(Item item) { |
| System.out.println("Saving " + item + " to file"); |
| } |
| } |
| ---- |
| |
| [start=7] |
| . Исправьте операторы импорта. Либо щелкните правой кнопкой мыши в редакторе и выберите 'Исправить выражения импорта' или нажмите Ctrl-Shift-I (⌘-Shift-I в Mac). В начало файла добавляются операторы импорта для `javax.annotation.PostConstruct` и `javax.annotation.PreDestroy`. |
| |
| [start=8] |
| . После этого добавьте новый компонент `ItemErrorHandler` к `ItemProcessor`. |
| |
| [source,java] |
| ---- |
| |
| @Named |
| @RequestScoped |
| public class ItemProcessor { |
| |
| @Inject @Demo |
| private ItemDao itemDao; |
| |
| @Inject |
| private ItemValidator itemValidator; |
| |
| *@Inject |
| private ItemErrorHandler itemErrorHandler;* |
| |
| public void execute() { |
| List<Item> items = itemDao.fetchItems(); |
| for (Item item : items) { |
| *if (!itemValidator.isValid(item)) { |
| itemErrorHandler.handleItem(item); |
| }* |
| } |
| } |
| } |
| ---- |
| |
| С помощью подсказки редактора добавьте оператор импорта для `exercise3.ItemErrorHandler`. |
| |
| |
| [start=9] |
| . Для запуска проекта нажмите кнопку 'Запустить проект' ( image:images/run-project-btn.png[] ). (В качестве альтернативы нажмите F6; fn-F6 в Mac) В браузере нажмите кнопку '`Выполнить`' на отображаемой странице. Переключите обратно в IDE и проверьте журнал сервера GlassFish, который отображается в окне вывода (Ctrl-4; ⌘-4 в Mac). |
| |
| [source,java] |
| ---- |
| |
| INFO: Creating file error reporter |
| INFO: Saving exercise2.Item@6257d812 [Value=34, Limit=7] to file |
| INFO: Saving exercise2.Item@752ab82e [Value=89, Limit=32] to file |
| INFO: Closing file error reporter |
| ---- |
| link:/about/contact_form.html?to=3&subject=Feedback:%20Using%20CDI%20Injection%20to%20Perform%20Custom%20Validation[+Отправить отзыв по этому учебному курсу+] |
| |
| |
| |
| [[seealso]] |
| == Дополнительные сведения |
| |
| Различные развертывания приложений могут использовать различные правила обработки недопустимых элементов: отклонение элементов, отправку уведомлений, выделение элементов или перечисление их в выходном файле. Кроме того, может потребоваться комбинация этих действий (например, отклонить заказ, отправить письмо менеджеру и записать заказ в файл). Оптимальным способом обработки такой многогранной проблемы является использование _событий_. События CDI рассматриваются в последнем примере этой серии. |
| |
| * link:cdi-events.html[+Обработка событий в CDI+] |
| |
| Дополнительные сведения о CDI и Java EE приведены в следующих материалах. |
| |
| * link:cdi-intro.html[+Начало работы со внедрением контекстов и зависимостей и JSF 2.0+] |
| * link:cdi-inject.html[+Работа с внедрением и квалификаторами в CDI+] |
| * 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: спецификация внедрения контекстов и зависимостей+] |
| * link:http://jcp.org/en/jsr/detail?id=316[+JSR 316. Платформа Java, спецификация Enterprise Edition 6+] |