在众多的Spring教学视频中,很少有课程去讲解SpringEvent相关功能使用的。或许是比较简单吧。引发对Event功能探究的原因是最近在看PIG开源项目,发现其中认证模块多处使用到了SpringEvent的功能。于是,准备翻翻官方文档做一个学习笔记。
1.简介
在ApplictionContext
中的事件发布和处理的操作,是由ApplictionEvent
和ApplictionListener
两个接口来实现的。当一个Bean实现了ApplictionListener
并加入了容器。当一个ApplictionEvent
发布到容器后,这个Bean就可以自动地获取到这个Event并进行处理。这是典型的观察者模式(Observer Pattern)
对于ApplictionEvent,Spring框架帮我们内置了好多:
- ContextRefreshedEvent
- ContextStartedEvent
- ContextStoppedEvent
2.自定义事件发布和获取
2.1自定义一个事件
- 类extends
ApplicationEvent
官方实例:
@Data
public class BlockedListEvent extends ApplicationEvent {
private final String address;
private final String content;
public BlockedListEvent(Object source, String address, String content) {
super(source);
this.address = address;
this.content = content;
}
// accessor and other methods...
}
2.2创建事件发布者
事件的发布需要使用Spring提供的ApplicationEventPublisher
来发布。或者通过ApplicationContext
也可以发布
@Component
public class EmailService implements ApplicationEventPublisherAware {
private ApplicationEventPublisher publisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
public void sendEmail(String address, String content) {
//发布事件
publisher.publishEvent(new BlockedListEvent(this, address, content));
}
}
2.3创建监听者
监听者可以获取到事件对象。具体的实现方式如下:
@Component
public class BlockedListNotifier implements ApplicationListener<BlockedListEvent> {
private String notificationAddress;
public void setNotificationAddress(String notificationAddress) {
this.notificationAddress = notificationAddress;
}
@SneakyThrows
@Override
public void onApplicationEvent(BlockedListEvent event) {
System.err.println("接收消息");
Thread.sleep(5000);
System.out.println(event);
// notify appropriate parties via notificationAddress...
}
}
2.4注意事项
- 同一类Event,在上一个没有处理完成时。永远不允许发送第二个
- 监听者的消费顺序是一个一个来的,不是并发
-
3.使用注解方式注册监听器
在前面我们注册一个监听者需要写一个类,如果要监听多个事件就要有多个类对象,但是大多数情况下可能逻辑就是记录个日志,所以注解方式可以实现一个Bean写多个方法处理不同的事件。每个方法处理一类或多类事件。
@EventListener
```java @Component public class MyListener { @EventListener public void commence(BlockedListEvent event){ System.err.println(“注解方式处理”); System.err.println(event);}
}
此外注解里值还可以对事件进行过滤和处理完后也发事件。具体内容用到时再仔细看一下。具体功能有:
1. 通过事件对象中的字段过滤
2. 处理完事件后,也发布一个事件
<a name="xpfTz"></a>
# 4.异步监听器
异步监听器没啥特别的,就是在方法上添加一个`@Async`注解
```java
@EventListener
@Async
public void processBlockedListEvent(BlockedListEvent event) {
// BlockedListEvent is processed in a separate thread
}
5.顺序监听器
不用说吧,@Order
注解来解决
@EventListener
@Order(42)
public void processBlockedListEvent(BlockedListEvent event) {
// notify appropriate parties via notificationAddress...
}
6.通用事件类型
在2节中,我们通过实现ApplicationEvent来定义自己的事件,但是其实我们的事件可能就是我们的一个实体类。于是乎,Spring提供了一个EntityCreatedEvent<T>
。T就是指定我们自己定义的实体类即可。
注:这个功能我没有实验出来,因为我没有这个类。不知道为啥。