Spring中事件监听器
概述
事件监听器是观察者模式的一个应用,当被观察的事件发生改变时需要通知该事件的订阅者针对这个事件做出对应行为。它将事件的发布和订阅进行解耦,因此可以独立修改事件发布或者订阅方便代码扩展和维护
基本构成
事件监听元素包括:事件(即事件对象如鼠标、数据对象)、事件源(即事件生产者如鼠标点击、修改数据对象等行为)、事件监听器(即事件订阅者当事件发生改变通知对应监听器进行处理)
Spring事件监听器应用
如进行下单时,下单成功会发送短信或者邮件通知,首先需要创建一个事件(继承ApplicationEvent),然后定义一个事件监听器用于处理下单成功发送短信或邮件(这里定义事件监听器有两种方式,一种是实现ApplicationListener接口中的onApplicationEvent方法,另外一种是在对应方法上添加@EventListener注解)
- 创建订单事件
/**
* @Classname OrderEvent
* @Description 订单自定义事件
* @Date 2022/8/7 18:17
* @Created by wsp
*/
public class OrderEvent extends ApplicationEvent {
public OrderEvent(Object source) {
super(source);
}
public OrderEvent(Object source, Clock clock) {
super(source, clock);
}
}
- 创建短信监听器和邮件监听器
/**
* @Classname SmsApplicationListener
* @Description 短信发送监听服务
* @Date 2022/8/7 18:08
* @Created by wsp
*/
@Slf4j
@Component
public class SmsApplicationListener implements ApplicationListener<OrderEvent> {
@Override
public void onApplicationEvent(OrderEvent event) {
try {
long timestamp = event.getTimestamp();
Object source = event.getSource();
log.info("短信监听器收到消息:{},时间戳为:{},消息源为:{}",event,timestamp,source);
} catch (Exception e) {
e.printStackTrace();
}
log.info("执行sms短信业务");
}
}
/**
* @Classname EmailApplicationListener
* @Description 邮件发送监听服务
* @Date 2022/8/7 18:08
* @Created by wsp
*/
@Slf4j
@Component
public class EmailApplicationListener{
@EventListener
public void getOrderEvent(OrderEvent event){
try {
long timestamp = event.getTimestamp();
Object source = event.getSource();
log.info("邮件监听器收到消息:{},时间戳为:{},消息源为:{}",event,timestamp,source);
} catch (Exception e) {
e.printStackTrace();
}
log.info("执行Email邮件业务");
}
}
- 发布事件
/**
* @Classname OrderServiceImpl
* @Description 模拟订单服务
* @Date 2022/8/7 17:54
* @Created by wsp
*/
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
OrderDao orderDao;
@Autowired
ApplicationContext context;
@Override
public Long generateOrder(Order order) {
order.setCreateTime(new Date());
order.setUpdateTime(new Date());
orderDao.save(order);
// 订单创建完成后,发送邮件或者短信通知(使用事件监听机制,发布事件)
context.publishEvent(new OrderEvent(order));
return order.getId();
}
}
Spring中监听器流程和源码解析
- 创建事件广播器
- 在Spring启动时会执行refresh方法进行刷新容器,其中会调用initApplicationEventMulticaster来创建一个事件广播器,后续它可以分发消息到对应的监听器中
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
//从容器中获取事件广播器applicationEventMulticaster
if (beanFactory.containsLocalBean("applicationEventMulticaster")) {
this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class);
...
} else {
//容器中没有该事件广播器则进行创建
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster);
...
}
}
}
- 注册事件监听器
- 当事件广播器创建完成,调用registerListeners方法注册事件监听器即将扫描到的事件加入到事件广播器中
rotected void registerListeners() {
Iterator var1 = this.getApplicationListeners().iterator();
//将环境自带Listener监听器加入到事件广播器中
while(var1.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var1.next();
this.getApplicationEventMulticaster().addApplicationListener(listener);
}
String[] listenerBeanNames = this.getBeanNamesForType(ApplicationListener.class, true, false);
String[] var7 = listenerBeanNames;
int var3 = listenerBeanNames.length;
//将实现ApplicationListener接口的Listener监听器加入到事件广播器中(仅bean名称)
for(int var4 = 0; var4 < var3; ++var4) {
String listenerBeanName = var7[var4];
this.getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
...
}
- 由于自定义事件监听器尚未初始化完成,因此会在ApplicationListenerDetectorl类调用postProcessAfterInitialization方法获取到监听器bean加入到事件广播器中
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof ApplicationListener) {
Boolean flag = (Boolean)this.singletonNames.get(beanName);
if (Boolean.TRUE.equals(flag)) {
this.applicationContext.addApplicationListener((ApplicationListener)bean);
}
...
}
}
return bean;
}
- 发布事件并触发监听
- 发布事件时即委托事件广播器找到对应事件监听器执行监听方法
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
Object applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent)event;
} else {
//若事件非ApplicationEvent类型则自动包装为PayloadApplicationEvent
applicationEvent = new PayloadApplicationEvent(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
}
}
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
} else {
//进行事件广播
this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType);
}
...
}
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
//事件类型为空获取event事件实例的类型作为默认类型
ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
//获取线程池(若配置线程池可异步执行)
Executor executor = this.getTaskExecutor();
//根据事件和事件类型找到对应Listener监听器
Iterator var5 = this.getApplicationListeners(event, type).iterator();
while(var5.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var5.next();
if (executor != null) {
executor.execute(() -> {
//调用监听器监听方法获取到监听事件,即listener.onApplicationEvent(event);
this.invokeListener(listener, event);
});
} else {
this.invokeListener(listener, event);
}
}
}
- @EventListener注解修饰的监听方法具体解析过程:会在bean初始化后执行EventListenerMethodProcessor类的afterSingletonsInstantiated方法,该类实现了SmartInitializingSingleton接口的afterSingletonsInstantiated方法当bean创建完成会触发这个接口方法,该方法会找到@EventListener所注解的方法将对应类通过eventListenerFactories事件监听器工厂进行反射创建并加入到事件广播器中