spring容器提供一种事件发布通知机制用来实现简单的消息通信,达到一定的业务解耦,开发人员可以使用Spring事件框架来定义和处理各种事件,是一种观察者模式的实现。
事件定义
要发布事件首先要定义事件,我们可以通过集成ApplicationEvent类来定义事件
java
public class MyEvent extends ApplicationEvent {
public MyEvent(Object source) {
super(source);
}
}
需要调用ApplicationEvent类构造函数来设置消息内容。
事件发布
事件的发布我们可以通过实现ApplicationEventPublisherAware接口,重写其setApplicationEventPublisher方法获取事件发布器。然后调用发布器的publishEvent方法发布事件
如下发布上面自定义的MyEvent事件
java
@Service
@Slf4j
public class EventService implements ApplicationEventPublisherAware {
//@Autowired
private ApplicationEventPublisher applicationEventPublisher;
//从写setApplicationEventPublisher 获取发布器
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
public void publish(String msg){
log.info("开始发送事件");
MyEvent event = new MyEvent(msg);
/**
* 默认事件的发送是同步处理
* 所以要在事件处理里控制好异常,否则会影响当前发布方法
*/
applicationEventPublisher.publishEvent(event);
log.info("结束事件处理");
}
}
这里setApplicationEventPublisher方法传入的publisher实际上就是context上下文,因为context实现了ApplicationEventPublisher接口。实现了ApplicationEventPublisherAware接口的bean会在ApplicationContextAwareProcessor后置处理器的before方法处调用其接口方法,完成回调赋值。
除了通过实现接口的方式,也可以直接使用@Autowired注解来注入事件发布器。
发布器的publishEvent(event)方法默认是同步方式进行调用的,所以在事件处理方法里一定要处理好异常,以免影响我们主业务逻辑。
除了同步方式调用,还可以配置为异步方式
如下自定义@Bean(name = "applicationEventMulticaster"),设置其taskExecutor即可。
java
@Bean(name = "applicationEventMulticaster")
public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
SimpleApplicationEventMulticaster eventMulticaster =
new SimpleApplicationEventMulticaster();
eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
return eventMulticaster;
}
具体原理在后面源码分析解读。
事件处理
定义消息处理器可以通过实现ApplicationListener接口来完成,该接口支持泛型指定一个具体类型消息E extends ApplicationEvent。当有匹配消息是,其onApplicationEvent方法会被调用。
如下定义处理MyEvent类型消息:
java
@Component
@Slf4j
@Order(1)
public class MyEventListener implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
log.info("receive event:"+event);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 使用@EventListener注解也可以定义事件监听器
* @param event
*/
@EventListener
@Order(2)
public void annotationListener(MyEvent event){
log.info("注解接收事件:"+event);
}
}
这里看到除了实现ApplicationListener接口外,还可以使用@EventListener注解的方式指定处理其。
如果定义了多个消息处理器,还可以使用 @Order注解来指定调用顺序,小的先执行。
源码分析
spring容器在初始化的过程中,有几步是初始化消息相关操作。来看容器重要初始化方法refresh里几个相关的操作
java
//1、初始化事件处理器
initApplicationEventMulticaster();
//2、初始化事件监听器
registerListeners();
//3、发布相关事件
finishRefresh();
1、初始化事件处理器会往beanFacotry添加一个SimpleApplicationEventMulticaster
java
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//这里常量APPLICATION_EVENT_MULTICASTER_BEAN_NAME的值是applicationEventMulticaster
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
}
事件发布时候会用到该类进行发布事件。看到这里很容易理解上面自定义applicationEventMulticaster使用异步方式处理消息的配置为什么可行。
2、初始化listener会获取配置的listener
java
protected void registerListeners() {
// Register statically specified listeners first.
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
//获取定义的ApplicationListener类型的bean
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
//将listner存到EventMulticaster里
getApplicationEventMulticaster里().addApplicationListenerBean(listenerBeanName);
}
//...
}
所以我们只要实现ApplicationListener接口,实现其onApplicationEvent方法,当一个事件发布时候,就可以接收到该事件。也可以通过@EventListener注解定义。这里会将所有的消息listeners存放到EventMulticaster里。
java
AbstractApplicationEventMulticaster{
DefaultListenerRetriever {
Set<ApplicationListener<?>> applicationListeners;
}
}
addListener最后会存放到applicationListeners变量里。
3、在第三步内部发布相关refresh完成的事件里会调到publishEvent(new ContextRefreshedEvent(this))方法发布一个事件。最后会调到getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);进行事件广播。这里getApplicationEventMulticaster就是上面第一步初始化的SimpleApplicationEventMulticaster。
multicastEvent广播事件方法
java
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();//获取执行器
//获取合适的listeners 广播事件
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {//有执行器就异步执行
executor.execute(() -> invokeListener(listener, event));
}
else {//同步执行
invokeListener(listener, event);
}
}
}
这里的Executor属性可以通过BeanPostProcessor后置拦截器进行赋值。或者根据第1步multicaster的初始化,会先从factory里查找有没有APPLICATION_EVENT_MULTICASTER_BEAN_NAME类型的bean,没有才new一个。所以我们可以显示的声明一个ApplicationEventMulticaster然后设置exexutor属性。
getApplicationListeners会根据消息类型进行listener的过滤
invokeListener就是调用listener.onApplicationEvent(event)方法。