Java Platform, Enterprise Edition (Java EE) 8
Учебник по Java EE

Назад Вперёд Содержание

Использование событий в приложениях CDI

События позволяют бинам взаимодействовать без какой-либо взаимозависимости объектов во время компиляции. Один компонент может определять событие, другой компонент может вызывать событие, и ещё один компонент может обрабатывать событие. Кроме того, события могут быть запущены асинхронно. Бины могут быть в разных пакетах и ​​даже в разных слоях приложения.

Определение событий

Событие состоит из следующего:

  • Объект события

  • Ноль или более типов квалификаторов

Например, в примере billpayment, описанном в Пример billpayment: использование событий и Interceptor-ов, бин PaymentEvent определяет событие, используя три свойства, для которых есть set- и get- методы:

    public String paymentType;
    public BigDecimal value;
    public Date datetime;

    public PaymentEvent() {
    }

В этом примере также определяются квалификаторы, которые различают два вида PaymentEvent. Каждое событие также имеет квалификатор по умолчанию @Any.

Использование методов-наблюдателей для обработки событий

Обработчик событий использует метод-наблюдатель для получения событий.

Каждый метод-наблюдатель принимает в качестве параметра событие определённого типа, аннотированное @Observes и любыми квалификаторами для этого типа события. Метод-наблюдатель уведомляется о событии, если объект события соответствует типу события и если все квалификаторы события соответствуют квалификаторам события метода-наблюдателя.

Метод-наблюдатель может принимать другие параметры в дополнение к параметру события. Дополнительные параметры являются точками инъецирования и могут объявлять квалификаторы.

Обработчик события PaymentHandler для примера billpayment определяет два метода-наблюдателя, по одному для каждого типа PaymentEvent:

public void creditPayment(@Observes @Credit PaymentEvent event) {
    ...
}

public void debitPayment(@Observes @Debit PaymentEvent event) {
    ...
}

Условные и транзакционные методы-наблюдатели

Методы-наблюдатели также могут быть условными или транзакционными:

  • Условный метод-наблюдатель уведомляется о событии, только если объект компонента, который определяет метод-наблюдатель, уже существует в текущем контексте. Чтобы объявить условный метод-наблюдатель, укажите notifyObserver=IF_EXISTS в качестве аргумента для @Observes:

    @Observes(notifyObserver=IF_EXISTS)

    Чтобы получить безусловное поведение по умолчанию, можно указать @Observes(notifyObserver=ALWAYS).

  • Транзакционный метод-наблюдатель уведомляется о событии до или после завершения транзакции, в которой произошло событие. Можно также указать, что уведомление должно появляться только после успешного или неудачного завершения транзакции. Чтобы указать метод-наблюдатель транзакции, используйте любой из следующих аргументов для @Observes:

    @Observes(during=BEFORE_COMPLETION)
    
    @Observes(during=AFTER_COMPLETION)
    
    @Observes(during=AFTER_SUCCESS)
    
    @Observes(during=AFTER_FAILURE)

    Чтобы получить стандартное нетранзакционное поведение по умолчанию, укажите @Observes(during=IN_PROGRESS).

    Метод-наблюдатель, который вызывается до завершения транзакции, может вызвать метод setRollbackOnly в объекте транзакции, чтобы вызвать откат транзакции.

Методы-наблюдатели могут генерировать исключения. Если транзакционный метод-наблюдатель выдает исключение, это исключение перехватывается контейнером. Если метод-наблюдатель не является транзакционным, исключение завершает обработку события, и никакие другие методы-наблюдатели для события не вызываются.

Порядок действий метода-наблюдателя

Прежде чем генерируется определённое уведомление наблюдателя о событии, контейнер определяет порядок вызова методов-наблюдателей для этого события. Порядок методов-наблюдателей устанавливается посредством объявления аннотации @Priority для параметра события метода-наблюдателя, как в следующем примере:

void afterLogin(@Observes @Priority(javax.interceptor.Interceptor.Priority.APPLICATION) LoggedInEvent event) { ... }

Обратите внимание на следующее:

  • Если аннотация @Priority не указана, значением по умолчанию является javax.interceptor.Interceptor.Priority.APPLICATION + 500.

  • Если двум или более методам-наблюдателям назначен одинаковый приоритет, порядок их вызова не определён и поэтому непредсказуем.

Генерация событий

Бин генерирует события, реализующие интерфейс javax.enterprise.event.Event. События могут быть сгенерированы синхронно или асинхронно.

Синхронная генерация событий

Чтобы активировать событие синхронно, вызовите метод javax.enterprise.event.Event.fire. Этот метод генерирует событие и уведомляет любые методы-наблюдатели.

В примере billpayment Managed-бин PaymentBean запускает соответствующее событие, используя информацию, полученную из пользовательского интерфейса. На самом деле существует четыре компонента событий, два для объекта события и два для выполнения содержательной части. Managed-бин инъецирует два бина события. Метод pay использует оператор switch для выбора события, которое нужно запустить, используя new для выполнения содержательной части.

    @Inject
    @Credit
    Event<PaymentEvent> creditEvent;

    @Inject
    @Debit
    Event<PaymentEvent> debitEvent;

    private static final int DEBIT = 1;
    private static final int CREDIT = 2;
    private int paymentOption = DEBIT;
    ...

    @Logged
    public String pay() {
        ...
        switch (paymentOption) {
            case DEBIT:
                PaymentEvent debitPayload = new PaymentEvent();
                // выполнение содержательной части...
                debitEvent.fire(debitPayload);
                break;
            case CREDIT:
                PaymentEvent creditPayload = new PaymentEvent();
                // выполнение содержательной части...
                creditEvent.fire(creditPayload);
                break;
            default:
                logger.severe("Invalid payment option!");
        }
        ...
    }

Аргументом метода fire является PaymentEvent, который включает содержательная часть. Инициированное событие затем используется методами-наблюдателями.

Генерация асинхронных событий

Чтобы активировать событие асинхронно, вызовите метод javax.enterprise.event.Event.fireAsync. Этот метод вызывает все разрешённые асинхронные наблюдатели в одном или нескольких разных потоках.

@Inject Event<LoggedInEvent> loggedInEvent;

public void login() {
    ...
    loggedInEvent.fireAsync( new LoggedInEvent(user) );
}

Вызов метода fireAsync() возвращается немедленно.

Когда события запускаются асинхронно, методы-наблюдатели уведомляются асинхронно. Следовательно, соблюдение порядка методов-наблюдателей не гарантировано, потому что вызов метода-наблюдателя и запуск асинхронных событий происходят в разных потоках.


Назад Вперёд Содержание
Логотип Oracle  Copyright © 2017, Oracle и/или её дочерних компаний. Все права защищены. Версия перевода 1.0.5 (Java EE Tutorial — русскоязычная версия)