在spring容器中是通过ApplicationEvent
类和ApplicationListener
接口来处理事件的.如果某个bean实现了ApplicationListener
接口并被部署到容器中, 那么每次对应的ApplicationEvent
被发布到容器中时,都会通知该bean.这是典型的观察者模式.
spring的事件默认是同步的,即调用publisEvent()
方法发布事件后, 它会处于阻塞状态, 直到onApplicationEvent
接收到事件并处理完返回之后才会继续往下执行, 这种单线程同步的好处是可以进行事务管理.
事件的异步发布机制参数ApplicationEventMulticaster
文档.
Spring提供的标准事件
Event | 说明 |
---|---|
ContextRefreshedEvent |
当容器被实例化或refreshed时发布.如调用refresh()方法, 此处的实例化是指所有的bean都已被加载,后置处理器都被激活,所有单例bean都已被实例化, 所有的容器对象都已准备好可使用. 如果容器支持热重载,则refresh可以被触发多次(XmlWebApplicatonContext支持热刷新,而GenericApplicationContext则不支持) |
ContextStartedEvent |
当容器启动时发布,即调用start()方法, 已启用意味着所有的Lifecycle bean都已显式接收到了start信号 |
ContextStoppedEvent |
当容器停止时发布,即调用stop()方法, 即所有的Lifecycle bean都已显式接收到了stop信号 , 关闭的容器可以通过start()方法重启 |
ContextClosedEvent |
当容器关闭时发布,即调用close方法, 关闭意味着所有的单例bean都已被销毁.关闭的容器不能被重启或refresh |
RequestHandledEvent |
这只在使用spring的DispatcherServlet时有效,当一个请求被处理完成时发布 |
自定义事件
编程式自定义事件
编程式自定义事件分为以下几步:
- 定义事件, 扩展
ApplicationEvent
接口. - 在需要发布事件处通过
ApplicationEventPublisher
发布事件. - 定义事件监听器, 有两种实现方式, 一是实现
ApplicationListener
接口, 在onApplicationEvent
方法中定义接收事件后的处理逻辑; 二是通过注解实现(spring 4.2) - 将事件监听器注册为一个bean
a. 定义事件
/**
* 继承ApplicationEvent接口
*/
public class BlackListEvent extends ApplicationEvent {
private static final long serialVersionUID = -1089664438671641456L;
private final String address;
private final String content;
// 构造方法中构建事件内容
public BlackListEvent(Object source, String address, String content) {
super(source);
this.address = address;
this.content = content;
}
public String getAddress() {
return address;
}
public String getContent() {
return content;
}
@Override
public String toString() {
return "BlackListEvent [address=" + address + ", content=" + content + "]";
}
}
b. 定义事件发布逻辑
/**
* 实现ApplicationEventPublisherAware, 获取ApplicationEventPublisher
* 通过ApplicationEventPublisher对象来发布事件
*/
public class EmailService implements ApplicationEventPublisherAware {
private ApplicationEventPublisher publisher;
private List<String> blackList;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
public void sendEmail(String address, String content) {
if (blackList.contains(address)) {
System.out.println("=============发布事件=============");
BlackListEvent event = new BlackListEvent(this, address, content);
publisher.publishEvent(event);
System.out.println(event);
return;
}
System.out.println("=============发送邮件=============");
}
public List<String> getBlackList() {
return blackList;
}
public void setBlackList(List<String> blackList) {
this.blackList = blackList;
}
}
c-1. 编程式定义事件监听器
/**
* 实现ApplicationListener
* 通过其泛型参数定义监听的事件的具体类型
*
*/
public class BlackListNotifier implements ApplicationListener<BlackListEvent> {
private String notificationAddress;
// 对接收到的事件进行处理
@Override
public void onApplicationEvent(BlackListEvent event) {
System.out.println("=========收到消息=============");
System.out.println(event);
}
public void setNotificationAddress(String notificationAddress) {
this.notificationAddress = notificationAddress;
}
public String getNotificationAddress() {
return this.notificationAddress;
}
}
c-2. 注解方式定义事件监听器
在事件处理方法上添加@EventListener
.用相应的事件作为参数
@EventListener
public void onApplicationEvent(BlackListEvent event) {
System.out.println("=========注解式处理事件 : 收到消息=============");
System.out.println(event);
}
d. 注册事件监听器
@Bean
public BlackListNotifier blackListNotifier() {
return new BlackListNotifier();
}
@EventListener
@EventListener
注解有三个参数:
- classes: class数组, 定义监听事件的类型, 可以代替监听方法参数功能相同.
- value: 与classes参数相同
- condition: 过滤条件定义, 可以应用SpEL.
示例:
@EventListener(condition = "#blEvent.content == 'foo'")
public void processBlackListEvent(BlackListEvent blEvent) {
// notify appropriate parties via notificationAddress...
}
通过# + 事件参数名称
引用事件, 即#blEvent
表示事件blEvent
. 通过事件的属性名可直接引用事件的属性.即上述事件中, 引用到了事件的content属性的值进行判断.
定义监听器的执行顺序
- 编程式, 实现
Ordered
接口. - 声明式,
@Order(30)
注解.
异步监听事件
用@Async
注解事件监听器.
注: 要开启对异步注解的支持.
- java配置通过
@EnableAsync
开启. - xml: <task:annotation-driven/>
注: 在xml配置中, 要在配置头文件中加入以下内容:
xmlns:task="http://www.springframework.org/schema/task"
http://www.springframework.org/schema/task
https://www.springframework.org/schema/task/spring-task.xsd
网友评论