3.2.6.4. Events
Бин Events
реализует функциональность публикации объектов-событий уровня приложения. События могут использоваться для передачи данных между слабо связанными компонентами приложения. Бин Events
является простым фасадом для объекта ApplicationEventPublisher
Spring Framework.
public interface Events {
String NAME = "cuba_Events";
void publish(ApplicationEvent event);
}
Этот бин имеет только один метод - publish()
, принимающий объект события. Метод Events.publish()
уведомляет все слушатели, зарегистрированные в приложении и подписанные на события того же типа, что и переданный объект. Вы может использовать класс-обёртку PayloadApplicationEvent
для публикации любых объектов в качестве событий.
См. также руководство Spring Framework.
- Обработка событий в компонентах приложения
-
Прежде всего, необходимо создать класс события. Он должен быть наследником класса
ApplicationEvent
. Класс события может включать любые дополнительные данные. Например:package com.company.sales.core; import com.haulmont.cuba.security.entity.User; import org.springframework.context.ApplicationEvent; public class DemoEvent extends ApplicationEvent { private User user; public DemoEvent(Object source, User user) { super(source); this.user = user; } public User getUser() { return user; } }
Бины могут публиковать события, используя бин
Events
:package com.company.sales.core; import com.haulmont.cuba.core.global.Events; import com.haulmont.cuba.core.global.UserSessionSource; import com.haulmont.cuba.security.global.UserSession; import org.springframework.stereotype.Component; import javax.inject.Inject; @Component public class DemoBean { @Inject private Events events; @Inject private UserSessionSource userSessionSource; public void demo() { UserSession userSession = userSessionSource.getUserSession(); events.publish(new DemoEvent(this, userSession.getUser())); } }
По умолчанию все события обрабатываются синхронно.
Есть два способа обработки событий:
-
Реализовать интерфейс
ApplicationListener
. -
Использовать аннотацию
@EventListener
для метода.
В первом случае, мы должны создать бин, реализующий интерфейс
ApplicationListener
с указанием типа события:@Component public class DemoEventListener implements ApplicationListener<DemoEvent> { @Inject private Logger log; @Override public void onApplicationEvent(DemoEvent event) { log.debug("Demo event is published"); } }
Второй способ может использоваться для сокрытия деталей реализации обработчика событий и обработки множества различных событий в одном бине:
@Component public class MultipleEventListener { @Order(10) @EventListener protected void handleDemoEvent(DemoEvent event) { // handle event } @Order(1010) @EventListener protected void handleUserLoginEvent(UserLoggedInEvent event) { // handle event } }
По умолчанию, события в Spring требуют модификаторов доступа
protected
,package
илиpublic
для методов, аннотированных@EventListener
. Обратите внимание, что модификаторprivate
не поддерживается.Методы, аннотированные
@EventListener
, не работают в services, JMX-бинах и других бинах с интерфейсами. При использовании@EventListener
в таком бине на старте приложения будет выброшено исключение:BeanInitializationException: Failed to process @EventListener annotation on bean. Need to invoke method declared on target class, but not found in any interface(s) of the exposed proxy type. Either pull the method up to an interface or switch to CGLIB proxies by enforcing proxy-target-class mode in your configuration.
Если необходимо обрабатывать событие в бине с интерфейсом, реализуйте в нем также интерфейс
ApplicationListener
с типом нужного события.Вы можете использовать интерфейс
Ordered
и аннотацию@Order
Spring Framework для указания порядка исполнения обработчиков событий. Все бины и обработчики событий платформы используют значениеorder
от 100 до 1000, таким образом, вы можете добавить обработчик событий как до, так и после обработчиков события платформы. Если вы хотите добавить свой обработчик события до обработчиков из платформы, то используйте значение меньше 100.См. также События логина.
-
- Обработка событий в экранах
-
Обычно, бин
Events
делегирует публикацию события объектуApplicationContext
. Для блока Web Client это поведение отличается от стандартного, вы можете использовать дополнительный интерфейс для классов событий -UiEvent
. Это интерфейс-маркер для событий, которые должны быть доставлены в экраны пользовательского интерфейса текущего экземпляра UI (текущей вкладки веб-браузера). Важно отметить, что экземпляры событий, реализующихUiEvent
, не доставляются в бины Spring и не могут быть обработаны за пределами UI.Пример класса события:
package com.company.sales.web; import com.haulmont.cuba.gui.events.UiEvent; import com.haulmont.cuba.security.entity.User; import org.springframework.context.ApplicationEvent; public class UserRemovedEvent extends ApplicationEvent implements UiEvent { private User user; public UserRemovedEvent(Object source, User user) { super(source); this.user = user; } public User getUser() { return user; } }
События публикуются при помощи бина
Events
из контроллера экрана так же, как и из бинов Spring:@Inject Events events; // ... UserRemovedEvent event = new UserRemovedEvent(this, removedUser); events.publish(event);
Чтобы обработать событие, вы должны объявить в экране метод с аннотацией
@EventListener
(ИнтерфейсApplicationListener
не поддерживается):@Order(15) @EventListener protected void onUserRemove(UserRemovedEvent event) { notifications.create() .withCaption("User is removed " + event.getUser()) .show(); }
Вы можете использовать аннотацию
@Order
, чтобы задать порядок вызова обработчиков события.Если класс события реализует
UiEvent
, и объект такого события опубликован при помощи бинаEvents
из потока UI, то будут вызваны обработчики событий этого типа в открытых на данный момент окнах и фреймах. Обработка событий синхронная. Только экраны и фреймы текущей активной вкладки веб-браузера получат уведомление о событии.