Spring 事件监听——ApplicationListener 原理探究
最近项目中看到有人用 ApplicationListener ,注释上说是异步执行,某同事说该异步调用就是个笑话。今天有空研究了下。
具体实现
- 定义事件监听器:定义ApplicationListener的实现类
- 定义事件Event:继承ApplicationEvent,具体的业务参数是绑定到事件中的
- 推送事件:applicationContext.pushEvent
定义事件监听器,在监听器中实现具体业务逻辑
/**
* @program: demo
* @author: Mr.Lemon
* @create: 2020/4/12
**/
@Component
public class DemoApplicationListener implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
String s = null;
System.out.println("do listener");
s.toString();
}
}
定义事件Event,将参数传入到监听器中
/**
* @program: demo
* @author: Mr.Lemon
* @create: 2020/4/12
**/
public class MyEvent extends ApplicationEvent {
/**
* Create a new {@code ApplicationEvent}.
*
* @param source the object on which the event initially occurred or with
* which the event is associated (never {@code null})
*/
public MyEvent(Object source) {
super(source);
}
}
推送事件,推送事件,触发监听动作
@Autowired
private ApplicationContext applicationContext;
@GetMapping("/push")
public String pushEvent() {
applicationContext.publishEvent(new MyEvent("111"));
return "ok";
}
源码实现
实现非常简单,没什么好说的,接下来看下源码实现,从applicationContext.publishEvent入手。
/**
* Publish the given event to all listeners.
* @param event the event to publish (may be an {@link ApplicationEvent}
* or a payload object to be turned into a {@link PayloadApplicationEvent})
* @param eventType the resolved event type, if known
* @since 4.2
*/
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
具体的实现应该是在 getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
继续往下走
@Override
public 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);
}
}
}
/**
* Invoke the given listener with the given event.
* @param listener the ApplicationListener to invoke
* @param event the current event to propagate
* @since 4.1
*/
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);
}
}
可以这里很关键,可以看到有个 Executor executor = getTaskExecutor(); 所以其实可以得到结论了:事件的监听执行是可以异步进行的,那么接下来研究下如何实现异步。
异步执行事件监听
Executor executor = getTaskExecutor();
是在 org.springframework.context.event.SimpleApplicationEventMulticaster#getTaskExecutor
那么,这个类是在什么时候进行定义的?回忆下springboot的启动过程:
SpringBoot.run -> org.springframework.boot.SpringApplication#refreshContext -> org.springframework.boot.SpringApplication#refresh
这里截取部分代码
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
可以看到上面有个 initApplicationEventMulticaster();
/**
* Name of the ApplicationEventMulticaster bean in the factory.
* If none is supplied, a default SimpleApplicationEventMulticaster is used.
* @see org.springframework.context.event.ApplicationEventMulticaster
* @see org.springframework.context.event.SimpleApplicationEventMulticaster
*/
public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
/**
* Initialize the ApplicationEventMulticaster.
* Uses SimpleApplicationEventMulticaster if none defined in the context.
* @see org.springframework.context.event.SimpleApplicationEventMulticaster
*/
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
解读下代码就是:如果容器定义了 applicationEventMulticaster 的bean,那么 applicationEventMulticaster 的具体实现就是该类,否则就是 SimpleApplicationEventMulticaster,所以,思路很简单了,我只要定义一个类,继承 SimpleApplicationEventMulticaster,然后在给 taskExecutor 赋值就行了
/**
* @program: demo
* @author: Mr.Lemon
* @create: 2020/4/12
**/
@Component("applicationEventMulticaster")
public class DemoMulticaster extends SimpleApplicationEventMulticaster {
public DemoMulticaster(){
setTaskExecutor(Executors.newSingleThreadExecutor());
}
}
总结
Spring的事件监听是可以实现异步的,只是需要对原本的类进行拓展