三、好处及应用场景
ApplicationContext 在运行期会自动检测到所有实现了 ApplicationListener 的 bean,并将其作为事件接收对象 。当我们与 spring 上下文交互触发 publishEvent 方法时,每个实现了 ApplicationListener 的 bean 都会收到 ApplicationEvent 对象 , 每个 ApplicationListener 可以根据需要只接收自己感兴趣的事件 。
这样做有什么好处呢?
在传统的项目中,各个业务逻辑之间耦合性比较强,controller 和 service 间都是关联关系,然而,使用 ApplicationEvent 监听 publisher 这种方式,类间关系是什么样的?我们不如画张图来看看 。
DemoPublisher 和 DemoListener 两个类间并没有直接关联,解除了传统业务逻辑两个类间的关联关系 , 将耦合降到最小 。这样在后期更新、维护时难度大大降低了 。

文章插图
ApplicationEvent 使用观察者模式实现,那什么时候适合使用观察者模式呢?观察者模式也叫 发布-订阅模式 , 例如,微博的订阅,我们订阅了某些微博账号,当这些账号发布消息时,我们都会收到通知 。
总结来说,定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新 , 从而实现广播的效果 。
四、源码阅读

文章插图
Spring中的事件机制流程:
- ApplicationEventPublisher是Spring的事件发布接口,事件源通过该接口的pulishEvent方法发布事件
- ApplicationEventMulticaster就是Spring事件机制中的事件广播器,它默认提供一个SimpleApplicationEventMulticaster实现,如果用户没有自定义广播器,则使用默认的 。它通过父类AbstractApplicationEventMulticaster的getApplicationListeners方法从事件注册表(事件-监听器关系保存)中获取事件监听器,并且通过invokeListener方法执行监听器的具体逻辑
- ApplicationListener就是Spring的事件监听器接口,所有的监听器都实现该接口,本图中列出了典型的几个子类 。其中RestartApplicationListnener在SpringBoot的启动框架中就有使用
- 在Spring中通常是ApplicationContext本身担任监听器注册表的角色,在其子类AbstractApplicationContext中就聚合了事件广播器ApplicationEventMulticaster和事件监听器ApplicationListnener , 并且提供注册监听器的addApplicationListnener方法
来到ApplicationEventPublisher 的 publishEvent 方法内部:
protected void publishEvent(Object event, @Nullable ResolvableType eventType) { if (this.earlyApplicationEvents != null) { this.earlyApplicationEvents.add(applicationEvent); } else {//getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); }}多播事件方法:@Overridepublic void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); Executor executor = getTaskExecutor(); // 遍历所有的监听者 for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {if (executor != null) {// 异步调用监听器executor.execute(() -> invokeListener(listener, event));}else {// 同步调用监听器invokeListener(listener, event);} }}invokeListener:protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) { ErrorHandler errorHandler = getErrorHandler(); if (errorHandler != null) {try {doInvokeListener(listener, event);}catch (Throwable err) {errorHandler.handleError(err);} } else {doInvokeListener(listener, event); }}doInvokeListener:private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) { try {// 这里是事件发生的地方listener.onApplicationEvent(event); } catch (ClassCastException ex) {...... }}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 移动携号转网需要取消哪些业务
- 如何实现SpringCloud全链路灰色发布?
- 如何查询手机业务套餐发什么短信 如何查询手机业务
- 55岁的王祖贤,叶落归根,定居湖州,在移动办业务,女神气质还在
- 十个使用Spring Cloud和Java创建微服务的实践案例
- SpringBoot整合ElasticSearch详解及相关使用方法
- 让Java起飞的技术...
- Spring Cache 缓存注解这样用,实在是太香了!
- 一文带你了解Spring Actuator
- Springboot之把外部依赖包纳入Spring容器管理的两种方式
