SpringEvent应用
让复杂业务解耦,让代码同时保持健壮与优雅是每个coder不懈的追求。或许你会直接上消息队列,可是
Spring event
一 使用
基本使用很简单,定义事件A,注册一个对A的监听器,然后发布这个事件。示意图如下:
具体代码和步骤:
定义事件
1
2
3
4
5
6
7
8
9import org.springframework.context.ApplicationEvent;
public class MyEvent extends ApplicationEvent {
private String name;
public MyEvent(Object source, String name) {
super(source);
this.name = name;
}
}注册一个监听器
1
2
3
4
5
6
7
public class MyEventListener implements ApplicationListener<MyEvent> {
public void onApplicationEvent(MyEvent event) {
System.out.println("event = " + event);
}
}定义自己的上下文
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static ApplicationContext getContext() {
return context;
}
}发布事件
1
2// 在需要调用的地方
ApplicationContextProvider.getApplicationContext().publishEvent(new MyEvent("Source", "enventName"));
二 源码分析
springEvent使用基本可以两步, 注册 + 发布,核心代码其实都在 ApplicationEventMulticaster 类
关键类:
- ApplicationListener (监听)
- ApplicationEventPublisher (发布)
- ApplicationEventMulticaster (管理)
注册
基本有两种便利的实现方式:1,实现实现ApplicationListener接口 ; 2,定义Bean中的方法,并使用EventListener注解
实现ApplicationListener方式注册
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17// org.springframework.context.support.ApplicationListenerDetector#postProcessAfterInitialization
// 后置处理所有的ApplicationListener
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof ApplicationListener) {
Boolean flag = this.singletonNames.get(beanName);
if (Boolean.TRUE.equals(flag)) {
// 注册,最终调用是 this.applicationEventMulticaster.addApplicationListener(listener)
// ApplicationEventMulticaster是SpringEvent的管理类
this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
}
else if (Boolean.FALSE.equals(flag)) {
// 不支持非单例Bean
}
}
return bean;
}
基于注解@EventListener的注册
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// org.springframework.context.event.EventListenerMethodProcessor#processBean
private void processBean(final String beanName, final Class<?> targetType) {
// 获取有EventListener注解的方法
Map<Method, EventListener> annotatedMethods = MethodIntrospector.selectMethods(targetType,
(MethodIntrospector.MetadataLookup<EventListener>) method -> AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
ConfigurableApplicationContext context = this.applicationContext;
// 所有
List<EventListenerFactory> factories = this.eventListenerFactories;
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) {
Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
// 将方法封装成ApplicationListenerMethodAdapter
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
}
// 注册到ApplicationContext,同上面使用方法注解一致
context.addApplicationListener(applicationListener);
break;
}
}
}
}
发布
1 | // 发布调用 |
三、注意事项
可以从源码看到,SpringEvent是依赖SpringIOC的,在启动(init)和关闭(destroy)阶段,不要使用
如果不指定事件类型,会接受都爱全部事件。SpringBoot中自有事件依照启动顺序依次有:
- ServletWebServerInitializedEvent
- ContextRefreshedEvent
- ApplicationStartedEvent
- AvailabilityChangeEvent
- ApplicationReadyEvent
SpringEvent默认顺序执行,如果外层有事务,Event中异常可能会导致事务回滚。因此建议使用线程池来异步执行事件。自定义线程池方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
public class EventConfig {
SimpleApplicationEventMulticaster applicationEventMulticaster() {
SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程池数量
executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
//最大线程数量
executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 5);
//线程池的队列容量
executor.setQueueCapacity(Runtime.getRuntime().availableProcessors() * 2);
//线程名称的前缀
executor.setThreadNamePrefix("springEvent-executor-");
executor.initialize();
multicaster.setTaskExecutor(executor);
return multicaster;
}
}SpringEvent适用于最终一致性,如果需要重试,推荐Spring-retry