Spring5源码12-监听器原理
1. 监听器的简单使用
自定义监听事件:
/**
* 自定义监听事件,需要实现序列化接口
*/
public class DemoEvent extends ApplicationEvent implements Serializable {
private static final long serialVersionUID = 0L;
private String msg;
public DemoEvent(Object source) {
super(source);
}
public DemoEvent(Object source, String msg) {
super(source);
this.msg = msg;
}
public void printMsg(){
System.out.println("msg = " + msg);
}
}
/**
* 事件需要实现序列化接口
*/
public class MessageEvent extends ApplicationEvent implements Serializable {
private static final long serialVersionUID = 0L;
public MessageEvent(String source) {
super(source);
}
@Override
public String toString() {
return "MessageEvent{" +
", source=" + source +
'}';
}
}
自定义监听器:
/**
* 自定义监听器
*/
@Component
public class DemoListener implements ApplicationListener<DemoEvent> {
@Override
public void onApplicationEvent(DemoEvent event) {
System.out.println("DemoListener onApplicationEvent run");
event.printMsg();
}
}
@Component
public class MessageEventListener implements ApplicationListener<MessageEvent> {
@Override
public void onApplicationEvent(MessageEvent event) {
System.out.println("MessageEventListener onApplicationEvent run");
}
}
@Component
public class MessageEventTwoListener implements ApplicationListener<MessageEvent> {
@Override
public void onApplicationEvent(MessageEvent event) {
System.out.println("MessageEventTwoListener onApplicationEvent run");
}
}
测试:
public class AnnotationMainTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(MainConfig.class);
//测试事件监听器
DemoEvent demoEvent = new DemoEvent("", "world");
context.publishEvent(demoEvent);
context.publishEvent(new MessageEvent(""));
}
}
测试结果:
当程序运行时,Spring 会按照顺序,先发出 DemoEvent
事件转给DemoListener
监听器,进行进一步的处理。在发送MessageEvent
事件转给MessageEventTwoListener
和MessageEventListener
监听器,进一步处理。
实际上,Spring是将所有的事件都发送给所有的监听者
,这一点在后面的源码分析中可以看出来。
2.源码分析
整个监听事件的流程其实很简单
2.1 初始化 事件广播器 - initApplicationEventMulticaster();
initApplicationEventMulticaster
的方法比较简单,考虑了两种情况
- 如果用户自定义了事件广播器,在使用用户自定义的事件广播器
- 如果用户没有自定义事件广播器,则使用默认的
ApplicationEventMulticaster
// 如果用户自定义了事件广播器,在使用用户自定义的事件广播器
// 如果用户没有自定义事件广播器,则使用默认的 ApplicationEventMulticaster
protected void initApplicationEventMulticaster() {
// 注册 ApplicationEventMulticaster 组件
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 如果用户自定义了事件广播器,则使用用户自定义
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
// 否则使用默认的事件广播器 SimpleApplicationEventMulticaster
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
上面的代码看起来很简单,一般情况下我们都是使用默认的事件广播器SimpleApplicationEventMulticaster
2.2 注册监听器 - registerListeners();
protected void registerListeners() {
// 把所有监听器保存到多播器的集合中
// Register statically specified listeners first.
// 硬编码方式注册的监听器处理
for (ApplicationListener<?> listener : getApplicationListeners()) {
// 保存到多播器中
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
// 获取ApplicationListener 在ioc容器中注册的bean的名字
// 配置文件注册的监听处理器
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
// 获取所有的监听器,并保存他们的名字在
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// Publish early application events now that we finally have a multicaster...
// 派发之前的一些早期事件
// 发布之前保存的需要发布的事件
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
// todo
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
2.3 事件的发布 - publishEvent
我们在 上面的Demo 中, 通过 context.publishEvent(demoEvent);
发布的事件最终会执行如下方法:
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// Decorate event as an ApplicationEvent if necessary
// 分析事件类型
ApplicationEvent applicationEvent;
// ApplicationEvent 接口下的事件
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
// 任意对象作为事件最终被封装到了 PayloadApplicationEvent
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
// 获取事件广播器进行广播事件广播。我们上面说了一般我们使用默认的事件广播器即 SimpleApplicationEventMulticaster
// 拿到多播器发送事件即可
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
// 寻找父类BeanFactory,继续发布消息
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
我们继续看 multicastEvent
方法如下,可以看到,当Spring事件产生的时候,默认会使用SimpleApplicationEventMulticaster#multicastEvent
方法来广播事件,遍历所有的监听器,并使用监听器中的 onApplicationEvent 方法来进行监听事件的处理
。而对于每个监听器来说,其实都可以获取到产生的事件,但使用进行处理由监听器自己决定。
// 事件派发 可以是异步的
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
// 观察者模式,把关注event事件的 所有监听器拿来,调用他们的onApplicationEvent()即可
// 获取匹配事件类型的事件事件监听器。
// 比如上面Demo中DemoListener 监听的是DemoEvent 事件类型,这里就是筛选出接受 DemoEvent 类型的监听器。
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
// 在invokeListener 方法中激活调用事件监听器的onApplicationEvent方法
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
3. 框图
参考文章
Spring5源码注释github地址 Spring源码深度解析(第2版) spring源码解析 Spring源码深度解析笔记 Spring注解与源码分析 Spring注解驱动开发B站教程
转载自:https://juejin.cn/post/7136390498377269256