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的事件監聽是可以實現異步的,只是需要對原本的類進行拓展