一、引言
在分布式场景下,实现同步转异步的方式有三种方式:
- 异步线程池执行;比如借助
@Async
注解,放到Spring自带的线程池中去执行,或者其他方式的异步线程去执行 - 放到消息队列中,在消费者的代码中异步的消费,执行相关的逻辑
- 基于Spring的事件机制,触发事件,在监听器里实现相关逻辑
二、概要
Spring事件发送监听涉及3个部分
- 事件源: 对应具体的事件。
- 事件监听器:,负责接收具体的事件源。
- 事件广播器(发送器):, 负责发布事件源。
相应的处理逻辑为:事件监听器会注册具体的事件源,当事件广播器广播具体的事件源后,事件监听器能接到该事件的发布消息,然后处理相关事件。
1.事件源
2.事件广播
Spring提供了ApplicationEventPublisher接口作为事件发布者,并且ApplicationContext接口继承了该接口,担当着事件发布者的角色。但ApplicationContext接口的具体实现各有差异。Spring提供了ApplicationEventMulticaster接口,负责管理ApplicationListener和发布ApplicationEvent。ApplicationContext接口会把事件的相关工作委托ApplicationEventMulticaster的实现类处理。发布事件context.publishEvent(event); 实际上是由ApplicationContext的实现AbstractApplicationContext执行发布事件的行为
执行SimpleApplicationEventMulticaster中的multicastEvent方法,调用事件监听器的onApplicationEvent()方法
3.事件监听器
三、Spring事件机制的使用
1.使用步骤
- 事件源extends ApplicationEvent
- 事件监听器implements ApplicationListener<事件源>并声明其为spring组件
声明组件这里要注意一点,在 Spring 中,有一些事件是在创建
ApplicationContext 之前触发的,比如 ApplicationStartingEvent 和
ApplicationEnvironmentPreparedEvent 等事件。这些事件是在 SpringBoot 启动过程的早期阶段触发的,因此您不能将这些事件上的侦听器注册@Bean。
为了解决早期事件注册侦听器的问题,SpringBoot提供了SpringApplication.addListeners()
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MySpringApplication.class);
app.addListeners(new NotifyListener());
app.run(args);
}
或者,src/main/resources/META-INF/spring.factories文件中声明:
org.springframework.context.ApplicationListener=com.xmc.event.NotifyListener
然而,普通事件上的侦听器采用 @EventListener,或者直接添加 @Component
@Configuration
public class NotifyListenerConfig {
@EventListener(NotifyEvent.class)
public void onApplicationStartedEvent(NotifyEvent event) {
System.out.println("配置方式:"+event.getContent());
System.out.println("配置方式:"+event.getEmail());
}
}
- 发布事件://发布事件context.publishEvent(event);
2.代码示例
事件源
public class NotifyEvent extends ApplicationEvent {
private String email;
private String content;
public NotifyEvent(Object source) {
super(source);
}
public NotifyEvent(Object source, String email, String content) {
super(source);
this.email = email;
this.content = content;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
事件监听器
@Component
public class NotifyListener implements ApplicationListener<NotifyEvent> {
@Override
public void onApplicationEvent(NotifyEvent event) {
System.out.println(event.getContent());
System.out.println(event.getEmail());
}
}
事件发布
@SpringBootTest
public class ListenerTest {
@Autowired
private WebApplicationContext webApplicationContext;
@Test
public void testListener() {
NotifyEvent event = new NotifyEvent("object", "abc@qq.com", "This is the content");
webApplicationContext.publishEvent(event);
}
}