在观察者模式中,一定要有一个管理维护监听者列表的功能。在Spring的事件机制中,将维护监听者列表的功能单独定义了一个接口,即ApplicationEventMulticaster接口。这也体现了单一责任原则的设计思想。我们看其源码:
public interface ApplicationEventMulticaster { /** * Add a listener to be notified of all events. * @param listener the listener to add */ void addApplicationListener(ApplicationListener listener); /** * Add a listener bean to be notified of all events. * @param listenerBeanName the name of the listener bean to add */ void addApplicationListenerBean(String listenerBeanName); /** * Remove a listener from the notification list. * @param listener the listener to remove */ void removeApplicationListener(ApplicationListener listener); /** * Remove a listener bean from the notification list. * @param listenerBeanName the name of the listener bean to remove */ void removeApplicationListenerBean(String listenerBeanName); /** * Remove all listeners registered with this multicaster. *
After a remove call, the multicaster will perform no action * on event notification until new listeners are registered. */ void removeAllListeners(); /** * Multicast the given application event to appropriate listeners. *
Consider using {@link #multicastEvent(ApplicationEvent, ResolvableType)} * if possible as it provides better support for generics-based events. * @param event the event to multicast */ void multicastEvent(ApplicationEvent event); /** * Multicast the given application event to appropriate listeners. *
If the {@code eventType} is {@code null}, a default type is built * based on the {@code event} instance. * @param event the event to multicast * @param eventType the type of event (can be {@code null}) * @since 4.2 */ void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType); }
可以看到,这个接口定义了增删查监听者的方法,所以,监听者列表的维护通过这个接口实现。需要注意的是这个接口还定义了multicastEvent方法。通过这个方法,将事件传给监听器。所以这个类,将事件和监听器,连接在一起。这里采用的是中介者模式,这个接口就是中介者角色。
ApplicationEventPublisher:
Spring设计的事件发布类,我们看其源码:
public interface ApplicationEventPublisher { /** * Notify all matching listeners registered with this * application of an application event. Events may be framework events * (such as ContextRefreshedEvent) or application-specific events. *
Such an event publication step is effectively a hand-off to the * multicaster and does not imply synchronous/asynchronous execution * or even immediate execution at all. Event listeners are encouraged * to be as efficient as possible, individually using asynchronous * execution for longer-running and potentially blocking operations. * @param event the event to publish * @see #publishEvent(Object) * @see org.springframework.context.event.ContextRefreshedEvent * @see org.springframework.context.event.ContextClosedEvent */ default void publishEvent(ApplicationEvent event) { publishEvent((Object) event); } /** * Notify all matching listeners registered with this * application of an event. *
If the specified {@code event} is not an {@link ApplicationEvent}, * it is wrapped in a {@link PayloadApplicationEvent}. *
Such an event publication step is effectively a hand-off to the * multicaster and does not imply synchronous/asynchronous execution * or even immediate execution at all. Event listeners are encouraged * to be as efficient as possible, individually using asynchronous * execution for longer-running and potentially blocking operations. * @param event the event to publish * @since 4.2 * @see #publishEvent(ApplicationEvent) * @see PayloadApplicationEvent */ void publishEvent(Object event); }
里面定义了publishEvent方法,进行事件的发布。但是事件不是直接发布到listener中,而是发布在ApplicationEventMulticaster类中,所以在ApplicationEventPublisher类中,一定会有ApplicationEventMulticaster对象,将事件发布到ApplicationEventMulticaster中。
事件流程总结:
通过上面几个类的描述,我们总结一下spring事件机制的流程:
流程的核心,就是PublishEvent。Event对象以参数的形式传入PublishEvent对象。然后将Event事件传入ApplicationEventMulticaster类中,由ApplicationEventMulticaster类将事件传给其维护的监听者,执行监听者方法。
领悟
由上面Spring设计事件模式思路我们可以感受到,Spring把单一的功能,都拎出来形成了一套接口规范,然后多个接口规范组合,去完成一件事情。所以我们在阅读源码时会感觉很乱。只要我们分析清楚每个对象的设计思路和作用是什么,再分析他们之间的组合完成了什么事情,就很容易理解其设计理念了。
应用
上面分析了Spring事件机制的运行原理,那么对我们实际开发中,有何帮助呢?
这就需要我们结合源码进行解读了。
笔者找到一篇写的很好的博文,大家可以参考:浅谈Spring事件监听。
我们可以自定义事件源,如下:
@Component
public class MyEventSource {
public void ccc(){
System.out.println("事件源方法");
}
}
然后定义Event对象,包装事件源:
@Component
public class MyEvent extends ApplicationEvent {
public MyEvent(MyEventSource source) {
super(source);
}
# 面试结束复盘查漏补缺
每次面试都是检验自己知识与技术实力的一次机会,面试结束后建议大家及时总结复盘,查漏补缺,然后有针对性地进行学习,既能提高下一场面试的成功概率,还能增加自己的技术知识栈储备,可谓是一举两得。
**以下最新总结的阿里P6资深Java必考题范围和答案**,包含最全MySQL、Redis、Java并发编程等等面试题和答案,用于参考~
**[CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】](https://codechina.csdn.net/m0_60958482/java-p7)**
**重要的事说三遍,关注+关注+关注!**


**更多笔记分享**
下最新总结的阿里P6资深Java必考题范围和答案**,包含最全MySQL、Redis、Java并发编程等等面试题和答案,用于参考~
**[CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】](https://codechina.csdn.net/m0_60958482/java-p7)**
**重要的事说三遍,关注+关注+关注!**
[外链图片转存中...(img-fEgc1Hqo-1630916338746)]
[外链图片转存中...(img-2Yh2wlDV-1630916338748)]
**更多笔记分享**
