3.2.6.4. Events
See Decouple Business Logic with Application Events guide to learn different examples of application events. |
Events
bean encapsulates the application-scope event publication functionality. Application events can be used to exchange information between loosely coupled components. Events
bean is a simple facade for ApplicationEventPublisher
of the Spring Framework.
public interface Events {
String NAME = "cuba_Events";
void publish(ApplicationEvent event);
}
It has only one method publish()
that receives an event object. Events.publish()
notifies all matching listeners registered with this application of an application event. You can use PayloadApplicationEvent
to publish any object as an event.
See also Spring Framework tutorial.
- Event handling in beans
-
First of all, we have to create a new event class. It should extend the
ApplicationEvent
class. An event class can contain any additional data. For instance: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; } }
Beans can publish an event using the
Events
bean: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())); } }
By default, all events are handled synchronously.
There are two ways to handle events:
-
Implement the
ApplicationListener
interface. -
Use the
@EventListener
annotation for a method.
In the first case, we have to create a bean that implements
ApplicationListener
with the type of our event:@Component public class DemoEventListener implements ApplicationListener<DemoEvent> { @Inject private Logger log; @Override public void onApplicationEvent(DemoEvent event) { log.debug("Demo event is published"); } }
The second way can be used to hide implementation details and listen for multiple events in a single bean:
@Component public class MultipleEventListener { @Order(10) @EventListener protected void handleDemoEvent(DemoEvent event) { // handle event } @Order(1010) @EventListener protected void handleUserLoginEvent(UserLoggedInEvent event) { // handle event } }
By default, Spring events require
protected
,package
orpublic
access modifiers for@EventListener
methods. Pay attention thatprivate
modifier is not supported.Methods with
@EventListener
annotation do not work in services, JMX beans and other beans with interfaces. If you define@EventListener
on such bean you will get the following error on application start: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.
If you need to listen to an event in a bean with interface, implement the
ApplicationListener
interface instead.You can use Spring Framework
Ordered
interface and@Order
annotation for event handlers ordering. All the platform beans and event handlers useorder
value between 100 and 1000, thus you can add your custom handling before or after the platform code. If you want to add your bean or event handler before platform beans - use a value lower than 100.See also Login Events.
-
- Event handling in UI screens
-
Usually,
Events
delegates event publishing to theApplicationContext
. On the web tier, you can use a special interface for event classes -UiEvent
. It is a marker interface for events that are sent to UIs screens in the current UI instance (the current web browser tab).Please note that
UiEvent
instances are not sent to Spring beans.Sample event class:
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; } }
It can be fired using
Events
bean from a window controller the same way as from a bean:@Inject Events events; // ... UserRemovedEvent event = new UserRemovedEvent(this, removedUser); events.publish(event);
In order to handle an event you have to define methods in UI screens with a special annotation
@EventListener
(ApplicationListener
interface is not supported):@Order(15) @EventListener protected void onUserRemove(UserRemovedEvent event) { notifications.create() .withCaption("User is removed " + event.getUser()) .show(); }
You can use
@Order
annotation for event listener ordering.If an event is
UiEvent
and fired using theEvents
bean from UI thread then opened windows and/or frames with such methods will receive the event. Event handling is synchronous. Only UI screens of the current web browser tab opened by the user receive the event.