Применение аннотации @Alternative и аннотаций жизненного цикла

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

Содержимое на этой странице применимо к IDE NetBeans 7.2, 7.3, 7.4 и 8.0

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

Этот учебный курс основан на записи блога Энди Гибсона (Andy Gibson) Начало работы с CDI. Часть 2. Внедрение. В нем рассматривается использование аннотации @Alternative для настройки приложения для различных развертываний, а также показано, как использовать аннотации жизненного цикла управляемых компонентов, например, @PostConstruct и @PreDestroy для совмещения внедрения CDI с функциональными возможностями спецификации управляемых компонентов Java EE 6

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


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

Программное обеспечение или материал Требуемая версия
IDE NetBeans Версия 7.2, 7.3, 7.4, 8.0, Java EE
Комплект для разработчика на языке Java (JDK) версия 7 или 8
Сервер GlassFish Open Source Edition 3.x или 4.x
cdiDemo2.zip неприменимо

Примечания

  • В комплект Java для IDE NetBeans также входит компонент GlassFish Server Open Source Edition, являющийся контейнером, совместимым с Java EE.
  • Пример проекта к этому учебному курсу можно загрузить здесь: cdiDemo3.zip

Обработка нескольких развертываний

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

Для наглядности рассмотрим следующий случай. ItemValidator добавляется в главный класс ItemProcessor. ItemValidator имеет две реализации: DefaultItemValidator и RelaxedItemValidator. В соответствие с требованиями к развертыванию в большинстве случаев требуется использовать DefaultItemValidator, а RelaxedItemValidator — в одном конкретном развертывании. Для этого создаются аннотации к каждому компоненту, а затем указывается компонент, который используется для данного развертывания путем добавления записей в файл приложения beans.xml .

На диаграмме CDI отображаются объекты, созданные в этом упражнении
  1. Начните работу с извлечения начального проекта из файла cdiDemo2.zip (см. выше таблицу необходимых ресурсов). Выберите File ("Файл") > Open Project ("Открыть проект") (Ctrl-Shift-O), затем выберите проект в его местоположении на компьютере.
  2. Щелкните правой кнопкой мыши узел проекта в окне "Проекты" и выберите команду "Свойства".
  3. Выберите категорию "Запуск" и убедитесь, что в списке "Сервер" выбран экземпляр GlassFish.
  4. Создайте интерфейс ItemValidator.

    Щелкните 'Создать файл' ( Кнопка 'Создать файл' ) или нажмите сочетание клавиш CTRL+N (⌘-N on Mac) для открытия мастера создания файлов.
  5. Выберите категорию Java, а затем команду "Интерфейс Java". Нажмите кнопку "Далее".
  6. Введите имя класса в ItemValidator и пакет exercise3.
  7. Нажмите кнопку "Завершить". Интерфейс будет создан и открыт в редакторе.
  8. Добавьте метод isValid(), который принимает в качестве параметра объект Item и возвращает логическое значение boolean.
    public interface ItemValidator {
        boolean isValid(Item item);
    }
    С помощью подсказки редактора добавьте оператор импорта для exercise2.Item.
  9. Расширьте класс ItemProcessor для добавления новой возможности. Откройте в редакторе ItemProcessor и внесите следующие изменения.
    @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.

  10. Создайте реализацию ItemValidator под названием DefaultItemValidator, которая просто сравнивает значение с предельным.

    В окне "Проекты" щелкните правой кнопкой пакет exercise3 и выберите команду "Создать" > "Класс Java". Дайте классу имя DefaultItemValidator и нажмите кнопку "Готово".

  11. В элементе DefaultItemValidator реализуйте ItemValidator и переопределите метод isValid() следующим образом.
    public class DefaultItemValidator implements ItemValidator {
    
        @Override
        public boolean isValid(Item item) {
            return item.getValue() < item.getLimit();
        }
    }

    С помощью подсказки редактора добавьте оператор импорта для exercise2.Item.

  12. Нажмите кнопку 'Запустить проект' (Кнопка 'Выполнить проект') на главной панели инструментов IDE. Файл скомпилирован и развернут в GlassFish, и страница приветствия приложения (process.xhtml) отображается в веб-браузере.
  13. Нажмите кнопку Выполнить на странице. Вернитесь в среду IDE и проверьте протокол сервера GlassFish. Журнал сервера отображается в окне вывода (Ctrl-4; ⌘-4 в Mac) на вкладке 'GlassFish'. В нем видно, что элементы проверяются и перечисляются только допустимые элементы, значение которых меньше предельного.
    INFO: Item =  [Value=34, Limit=7] valid = false
    INFO: Item =  [Value=4, Limit=37] valid = true
    INFO: Item =  [Value=24, Limit=19] valid = false
    INFO: Item =  [Value=89, Limit=32] valid = false
    Окно вывода - журнал сервера GlassFish
  14. Теперь рассмотрим случай, в котором вам необходимо выполнить развертывание в другом месте, менее жестком, считающим компонент недопустимым только в том случае, если его значение более чем в два раза превышает ограничение. Может потребоваться другой компонент для реализации интерфейса ItemValidator для данной логики.

    Создайте новую реализацию ItemValidator с именем RelaxedItemValidator. В окне "Проекты" щелкните правой кнопкой пакет exercise3 и выберите команду "Создать" > "Класс Java". Дайте классу имя RelaxedItemValidator и нажмите кнопку "Готово".

  15. Сделайте RelaxedItemValidator реализацией ItemValidator и переопределите метод isValid() следующим образом.
    public class RelaxedItemValidator implements ItemValidator {
    
        @Override
        public boolean isValid(Item item) {
            return item.getValue() < (item.getLimit() * 2);
        }
    }

    С помощью подсказки редактора добавьте оператор импорта для exercise2.Item.

  16. Для запуска проекта нажмите кнопку 'Запустить проект' ( Кнопка 'Выполнить проект' ). Обратите внимание, что теперь развертывание проекта завершается сбоем.
  17. Проверьте журнал сервера в окне вывода (Ctrl-4; ⌘-4 в Mac). В протоколе отображается сообщение об ошибке неоднозначной зависимости. Это происходит по причине того, что имеются два класса, реализующих один и тот же интерфейс.
    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 , которое уникально для каждой реализации.

  18. Добавьте аннотацию @Alternative и соответствующий оператор импорта в RelaxedItemValidator и DefaultItemValidator.

    Откройте в редакторе RelaxedItemValidator и внесите следующие изменения.
    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.

    Всплывающее окно документации Javadoc в редакторе

    Переключитесь к DefaultItemValidator (нажмите сочетание клавиш CTRL+TAB) и внесите следующее изменение.

    import javax.enterprise.inject.Alternative;
    ...
    
    @Alternative
    public class DefaultItemValidator implements ItemValidator {
    
        public boolean isValid(Item item) {
            return item.getValue() < item.getLimit();
        }
    }

    Выполняя развертывание приложения сейчас, вы получите ошибку "неудовлетворенная зависимость", так как два подходящих компонента были определены как альтернативные, но ни один из них не был активирован в файле beans.xml .

  19. С помощью диалогового окна "Переход к файлу" в среде IDE откройте файл beans.xml . Выберите пункт "Переход" > "Переход к файлу" в главном меню среды IDE (сочетание клавиш ALT+SHIFT+O; CTRL+SHIFT+O в Mac OS), затем введите beans. Нажмите кнопку "ОК". Диалоговое окно 'Перейти к файлу'
  20. Внесите следующие изменения в файл beans.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 позволяет связать различные версии файла с различными развертываниями.

  21. Для запуска проекта нажмите кнопку 'Запустить проект' ( Кнопка 'Выполнить проект' ). (В качестве альтернативы нажмите F6; fn-F6 в Mac) В браузере нажмите кнопку 'Выполнить' на отображаемой странице. Переключите обратно в IDE и проверьте журнал сервера GlassFish, который отображается в окне вывода (Ctrl-4; ⌘-4 в Mac).
    INFO: Item =  [Value=34, Limit=7] valid = false
    INFO: Item =  [Value=4, Limit=37] valid = true
    INFO: Item =  [Value=24, Limit=19] valid = true
    INFO: Item =  [Value=89, Limit=32] valid = false

    Используется реализация RelaxedItemValidator, а третий элемент отображается как верный, хотя значение (24) больше заданного предела (19).


Применение аннотаций жизненного цикла к управляемым компонентам

В этом упражнении ItemErrorHandler будет добавлен в главный класс ItemProcessor. Для добавления выбран FileErrorReporter, поскольку он является единственной реализацией интерфейса ItemErrorHandler. Для настройки зависящих от жизненного цикла действий класса следует использовать аннотации @PostConstruct и @PreDestroy из спецификации управляемых компонентов (включенной в JSR 316: спецификация платформы Java, Enterprise Edition 6).

На диаграмме CDI отображаются объекты, созданные в этом упражнении

После этого необходимо создать интерфейс ItemErrorHandler для обработки обнаруженных недопустимых элементов.

  1. В окне "Проекты" щелкните правой кнопкой пакет exercise3 и выберите команду "Создать" > "Интерфейс Java".
  2. В мастере интерфейсов Java введите имя класса ItemErrorHandler и имя пакета exercise3. Нажмите кнопку "Завершить".

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

  3. Добавьте метод handleItem(), принимающий параметр типа Item.
    public interface ItemErrorHandler {
        void handleItem(Item item);
    }

    С помощью подсказки редактора добавьте оператор импорта для exercise2.Item.

  4. Выполните реализацию ItemErrorHandler с фиктивным обработчиком FileErrorReporter, сохраняющим данные элемента в файл.

    В окне "Проекты" щелкните правой кнопкой пакет exercise3 и выберите команду "Создать" > "Класс Java". Присвойте классу имя FileErrorReporter и нажмите кнопку "Готово".

  5. Сделайте FileErrorReporter реализацией ItemErrorHandler и переопределите метод handleItem() следующим образом.
    public class FileErrorReporter implements ItemErrorHandler {
    
        @Override
        public void handleItem(Item item) {
            System.out.println("Saving " + item + " to file");
        }
    }

    С помощью подсказки редактора добавьте оператор импорта для exercise2.Item.

    Вам нужно открыть файл до начала обработки элементов, оставить его открытым в течение процесса добавления содержимого в данный файл, а затем закрыть его по завершении процесса. Можно вручную добавить методы initProcess() и finishProcess() к компоненту средства сообщения об ошибке, но в этом случае вы не сможете выполнить кодирование интерфейса, так как вызывающей стороне будет необходимо знать данные специфичные для класса методы. Можно добавить те же методы к интерфейсу ItemErrorReporter, но в этом случае потребуется выполнить ненужное внедрение данных методов в каждый класс, реализующий данный интерфейс. Вместо этого можно использовать несколько аннотаций жизненного цикла из спецификации управляемых компонентов (входящей в JSR 316: спецификация платформы Java, Enterprise Edition 6) для вызова методов в компоненте в конкретных точках жизненного цикла компонента. Метод с аннотацией @PostConstruct вызывается после создания компонента и учета всех его зависимостей. Метод с аннотацией @PreDestroy аналогичным образом вызывается непосредственно перед удалением компонента контейнером.

  6. Добавьте следующие методы init() и release() с аннотациями @PostConstruct и @PreDestroy.
    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");
        }
    }
  7. Исправьте операторы импорта. Либо щелкните правой кнопкой мыши в редакторе и выберите 'Исправить выражения импорта' или нажмите Ctrl-Shift-I (⌘-Shift-I в Mac). В начало файла добавляются операторы импорта для javax.annotation.PostConstruct и javax.annotation.PreDestroy.
  8. После этого добавьте новый компонент ItemErrorHandler к ItemProcessor.
    @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.

  9. Для запуска проекта нажмите кнопку 'Запустить проект' ( Кнопка 'Выполнить проект' ). (В качестве альтернативы нажмите F6; fn-F6 в Mac) В браузере нажмите кнопку 'Выполнить' на отображаемой странице. Переключите обратно в IDE и проверьте журнал сервера GlassFish, который отображается в окне вывода (Ctrl-4; ⌘-4 в Mac).
    INFO: Creating file error reporter
    INFO: Saving  [Value=34, Limit=7] to file
    INFO: Saving  [Value=89, Limit=32] to file
    INFO: Closing file error reporter

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

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

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

get support for the NetBeans

Support


By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2013, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo