Spring 事件监听——ApplicationListener 原理探究

Spring 事件监听——ApplicationListener 原理探究

最近项目中看到有人用 ApplicationListener ,注释上说是异步执行,某同事说该异步调用就是个笑话。今天有空研究了下。

具体实现

  1. 定义事件监听器:定义ApplicationListener的实现类
  2. 定义事件Event:继承ApplicationEvent,具体的业务参数是绑定到事件中的
  3. 推送事件: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的事件监听是可以实现异步的,只是需要对原本的类进行拓展

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值