3.2.6.4. Events
参考 用应用程序事件解耦业务逻辑 向导,了解应用程序事件的不同示例。 |
Events
bean 封装了应用程序范围内的事件发布功能。应用程序事件可用于在松耦合的组件之间交换信息。Events
bean 是 Spring Framework 的 ApplicationEventPublisher
的简单外观设计模式实现。
public interface Events {
String NAME = "cuba_Events";
void publish(ApplicationEvent event);
}
此接口只有接收一个事件对象作为参数的 publish()
方法。Events.publish()
会通知所有应用程序内注册的匹配的监听器。可以使用 PayloadApplicationEvent
将任何对象发布为事件。
另请参阅 Spring 框架入门
- bean 中的事件处理
-
首先,创建一个新的事件类,继承
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; } }
Bean 对象可以使用
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())); } }
默认情况下,所有事件都是同步处理的。
处理事件有两种方法:
-
实现
ApplicationListener
接口。 -
方法使用
@EventListener
注解。
在第一种情况下,必须创建一个实现
ApplicationListener
接口的 bean,以需要事件类型作为泛型参数:@Component public class DemoEventListener implements ApplicationListener<DemoEvent> { @Inject private Logger log; @Override public void onApplicationEvent(DemoEvent event) { log.debug("Demo event is published"); } }
第二种方法可用于隐藏实现接口的细节并在单个 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 } }
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.
如果确实需要在带有接口的 bean 中监听事件,可以通过实现
ApplicationListener
接口来代替。可以使用 Spring 框架的
Ordered
接口和@Order
注解来对事件处理方法排序。框架中所有 bean 和事件处理方法使用的是 100 到 1000 之间的order
值,因此可以在框架的 order 值之前或之后添加自定义的处理顺序。如果要在平台 bean 之前添加 bean 或事件处理程序,可使用小于 100 的值。另请参阅登录事件.
-
- UI 界面中的事件处理
-
通常,
Events
将事件的发布委托给ApplicationContext
执行。在 Web 层,可以为事件类使用特殊的接口 -UiEvent
。这是一个事件的标记接口,实现这个接口的事件被发送到当前 UI 实例中的 UI 界面(当前 Web 浏览器标签页)。请注意,
UiEvent
实例不会发送到 Spring bean。示例事件类:
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
bean 触发事件,使用方式和在 bean 中一样:@Inject Events events; // ... UserRemovedEvent event = new UserRemovedEvent(this, removedUser); events.publish(event);
为了处理事件,必须在 UI 界面中使用注解
@EventListener
定义方法(不支持ApplicationListener
接口):@Order(15) @EventListener protected void onUserRemove(UserRemovedEvent event) { notifications.create() .withCaption("User is removed " + event.getUser()) .show(); }
可以使用
@Order
注解为事件监听器设定执行顺序。如果一个事件是
UiEvent
并使用来自 UI 线程的Events
bean 触发,那么带有@EventListener
方法的打开的窗口或 frame 将接收到该事件。事件处理是同步的。只有用户打开的当前 Web 浏览器标签页中 UI 界面才会收到该事件。