首先要说明的是Spring-boot的事件通知机制并不是Spring-boot的功能,而是Spring具有的功能。

0x00、使用篇

从用法上讲是很简单的,一般分为三步

一、定义事件源

创建一个事件源类继承ApplicationEvent这个类,这个类构造函数默认有个 source 的入参数,用来方便事件传参数,定义一个事件类的代码类似如下:

import org.springframework.context.ApplicationEvent;

/**
 * Created by 席有芳 on 2018/7/7.
 *
 * @author 席有芳
 */
public class StartedEvent extends ApplicationEvent {
    /**
     * Create a new ApplicationEvent.
     *
     * @param source the object on which the event initially occurred (never {@code null})
     */
    public StartedEvent(Object source) {
        super(source);
    }
}

二、定义事件监听器

首先要注意的是事件监听器是Spring的一个bean,所以一定要加上@Component这个注解或者类似的定义bean的注解,在需要处理事件的方法上加上@EventListener的注解并指定事件源,大致代码如下:

@Component
public class ShowUIEventListener {
  
    @EventListener(StartedEvent.class)
    public void showUI(StartedEvent startedEvent) {
		//具体业务逻辑
    }
}	

一个事件源可以绑定多个事件监听器,只要在不同的bean方法上加上同样的 @EventListener 注解就行,可以通过加上 @Order 注解控制监听器的执行顺序。可以通过 event.getSource() 获取到构造函数时候指定的对象。

三、发布并执行事件

通过 applicationContext.publishEvent(event); 的方式发布一个事件,事件发布完成后会自动触发并执行相关的EventListener 。

使用方法就是这么简单。然后我们来具体分析spring的源码实现。

0x01、原理篇

首先根据publishEvent的方法可以发现 Spring的ApplicationEventPublisher.java这个接口定一个了 publishEvent 相关的方法。追踪源码发现具体实现在 AbstractApplicationContext.java 这个类中。这个类中会通过 ApplicationEventMulticaster 来广播事件,具体代码如下:

源码很清晰,同时也可以发现如果是SpringMVC这种子容器定义的事件也会同步广播到父容器中。
接着看看广播器的源码

主要就两个部分,第一部分根据事件源提取出事件类型,第二步根据事件源与事件类型获取到对应的bean 并执行相关的方法。
getApplicationListeners 这个方法在 AbstractApplicationEventMulticaster 类中实现,具体逻辑大致是 首先去缓存里获取如果获取不到则调用retrieveApplicationListeners方法获取。
getApplicationListeners方法如下:

retrieveApplicationListeners方法如下:

代码很明显,容器的bean中找出满足规则的Listener组成一个列表,并放到缓存里。

打赏
Spring-boot事件通知机制用法与原理分析
Tagged on:         

发表评论