一.spring事件三大组件
1.1.事件
1.2.事件监听器
1.3.事件广播器(多播器)
二.事件流程图
概念:以下图为例,每次发布的一条新闻就可以理解为一个事件,上面的主持人就是事件的发布者,下面的记者就是事件的监听者。
spring事件是基于观察者设计模式
2.1.spring内置事件
例如spring容器启动完毕,以及销毁等等都会产生内置事件,这里不作介绍
2.2.自定义事件
CustomEvent 继承 ApplicationEvent,然后写一个自定义的监听器,放入spring容器中,去监听自定义的事件.
三.对应代码
3.1.代码示例
package com.shadow.wang.event.custom;
import org.springframework.context.ApplicationEvent;
public class CustomEvent extends ApplicationEvent {
private String name;
public String getName() {
return name;
}
public CustomEvent(Object source, String name) {
super(source);
this.name = name;
}
/**
* Create a new {@code ApplicationEvent}.
*
* @param source the object on which the event initially occurred or with
* which the event is associated (never {@code null})
*/
public CustomEvent(Object source) {
super(source);
}
}
package com.shadow.wang.event.custom;
import com.shadow.wang.guess.Student;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class CustomAnnoEventListener {
@EventListener(CustomEvent.class)
public void Listen(CustomEvent s){
System.out.println("CustomAnnoEventListener <===== " + s.getName());
}
}
package com.shadow.wang.event.custom;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class CustomEventListener implements ApplicationListener<CustomEvent> {
@Override
public void onApplicationEvent(CustomEvent event) {
System.out.println("event = " + event);
System.out.println(" CustomEventListener listen event ====>" + event.getName() + ", source = "+ event.getSource());
}
}
package com.shadow.wang.event;
import com.shadow.wang.event.custom.CustomEvent;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.stereotype.Component;
@Configuration
@ComponentScan("com.shadow.wang.event")
public class EventAppConfig {
@Test
public void learnEvent(){
AnnotationConfigApplicationContext
app = new AnnotationConfigApplicationContext(EventAppConfig.class);
app.publishEvent(new CustomEvent(this,"生产OOM"));
System.out.println("main线程执行中......");
Student bean = app.getBean(Student.class);
System.out.println("bean = " + bean);
}
@Bean
public ApplicationEventMulticaster applicationEventMulticaster(){
SimpleApplicationEventMulticaster simpleCaster = new SimpleApplicationEventMulticaster();
// 支持异步
simpleCaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
return simpleCaster;
}
}
@Component
class Student{
private String name;
}
执行结果图:这里可以看到我自定的2个监听器,都监听到了我自定义的 “生产OOM“事件,一种是实现ApplicationListener接口,另外一种是基于注解@LEventListener的实现
3.2.这里通过@Bean方式弄了一个异步广播器放入spring容器中 ,默认情况下spring容器中的广播器是同步的
这里可以观察后,下述的“日志打印,main线程在执行中”跑到了最上面
四.源码学习
为啥这二种监听器都有效果?
它们都被放入到了广播器(多播器)中
它们在执行时机(调用链路)是啥? 这些监听器啥时候放入广播器中的?
4.1.基于ApplicationListener
调用ApplicationListener的onApplicationEvent方法,走入自己写的实现类 CustomEventListener#onApplicationEvent
- 4.1.1 通过BeanPostProcessor的初始化后方法添加
ApplicationListenerDetector#postProcessAfterInitialization
- 4.1.2.通过spring容器的refresh()里面的注册一个监听器(查缺补漏,防漏lazy情况下的监听器没被注册上去)
4.2.基于注解@EventListener
调用到了ApplicationListenerMethodAdapter的onApplicationEvent方法,最终走了反射this.method.invoke(bean, args)
在实例化spring容器的reade解析器(AnnotatedBeanDefinitionReader)时,提前准备好了2个类
EventListenerMethodProcessor,DefaultEventListenerFactory来添加监听器到广播器中
注解类型的监听器@EventListener(CustomEvent.class) 执行时机是在那八大BeanPostprocessor执行完之后再去执行的,利用了一个特殊的处理器方法SmartInitializingSingleton的afterSingletonsInstantiated方法添加的
五.小结
spring事件是基于观察者设计模式,它默认情况下是线程同步机制,广播器中设置异步执行后,可支持异步机制。监听器的形式有两种,基于接口和基于注解@EventListener的形式。