Springboot事件监听机制:工作原理

Myth丶恋晨 2024-03-31 16:10 149阅读 0赞

目录

前言

1.观察者模式

1.1观察者模式的核心元素

1.2观察者模式的工作流程

2.springboot事件监听机制的基本工作原理

2.1事件发布器是什么时候在哪里产生的呢?

2.2事件监听器是什么时候怎么注册到事件发布器里去了呢

2.3事件发布器发布事件后,发生了什么?是怎么执行的监听器的回调方法了呢?

3.总结


前言

这是继《springboot事件监听机制一:实战应用》第二篇,知其然,当然还要知其所以然,深入的源码里面探寻一下这一有套机制的工作原理。spring生态很茂盛,这里不会站太高去分析这个问题,大扯spring的一些原理,而是以一个求知者的心态去探索spring监听机制的秘密,可能我分析得并不透彻,但我想如果能给看到这篇文章的你带去一些灵感或者触动也是好的。罗马不是一天就能建立起来的,想要弄懂它也非一天的事,多想多看总会明白的。另外看源码的时候,一定是带着问题去探寻,时刻把握好问题的核心,切忌被旁枝末节打扰而迷失的源码里了(如果对一旁枝末节实在很感兴趣,可以先记录下来位置,之后再来探寻)。发现问题,然后解决问题,这就是进步!现在一起来进步吧!

1.观察者模式

1.1观察者模式的核心元素

springboot事件监听机制的原理是观察者模式,观察者模式有几个核心的元素:

  • 事件源
  • 事件
  • 事件发布器
  • 监听器

1.2观察者模式的工作流程

  1. 事件监听器注册到事件发布器,用于监听事件
  2. 事件源产生事件,然后向发布器发布事件,
  3. 事件发布器回调已注册的监听器的回调方法
  4. 事件监听器的回调方法被调用

a3dc0cfbd30a4256a42eefb2bab27d64.png

2.springboot事件监听机制的基本工作原理

正如上一篇文章中的示例,把各业务中的短信发送需求抽象成一个短信发事件,在各业务需要发送短信的时候,就通过事件发布器来发布事件,然后触发短信发送监听器里的发送短信操作一样,Spring生态这么庞大,功能也多,自身的事件自不会少,如容器启动、容器刷新、关闭、停止等都是一个事件。为什么会这样呢?这是因为Spring容器在初始化、启动、刷新、关闭等这些过程中,也需要通知其他模块,所以spring自身也有很多事件也就不奇怪了。 但是这么多事件,功能不一样,但是本质是相同的,所有事件一基类都是java.util.EventObject。所以下面还是以上一篇文章中的短信发布事件作为例子,来探寻一下springboot的事件监听的工作原理。

34ae4c3c90994868a54f14375a348d5d.png

在上一篇的例子中,封装好短信事件,同是也把短信监听器通过@component注解注册到了spring容器里,然后就在业务中直接通过事件发布器(ApplicationEventPublisher)发布了,这中间许多细节是什么样的呢?比如:

  • 事件发布器是什么时候在哪里产生的呢?
  • 事件监听器是什么时候什么注册到事件发布里去了呢
  • 事件发布器发布事件后,是怎么执行的监听器的回调方法了呢?

2.1事件发布器是什么时候在哪里产生的呢?

事件发布器实例化的入口AbstractApplicationContext#refresh中调用了AbstractApplicationContext#initApplicationEventMulticaster,最后实际会实例出一个SimpleApplicationEventMulticaster对象,这个对象一般都翻译成事件广播器,他的作用就是发布事件、接受监听器的注册、回调监听器中的回调方法。眼尖的人都看出来了,在业务类里注册的事件发布器是ApplicationEventPublisher,不是SimpleApplicationEventMulticaster。先别急,这个疑问先留着,下面揭晓。

  1. protected void initApplicationEventMulticaster() {
  2. ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  3. if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
  4. this.applicationEventMulticaster =
  5. beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
  6. if (logger.isTraceEnabled()) {
  7. logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
  8. }
  9. }else {
  10. //spring容器启动的时候,applicationEventMulticaster还没有创立,会走这里
  11. this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
  12. beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
  13. if (logger.isTraceEnabled()) {
  14. logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
  15. "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
  16. }
  17. }
  18. }

2.2事件监听器是什么时候怎么注册到事件发布器里去了呢

事件监听器注册到事件发布器里的逻辑在这个方法:AbstractApplicationContext#registerListeners,而registerListeners()也是在refresh()里被调用的

  1. protected void registerListeners() {
  2. // Register statically specified listeners first.
  3. for (ApplicationListener<?> listener : getApplicationListeners()) {
  4. getApplicationEventMulticaster().addApplicationListener(listener);
  5. }
  6. //smsListener通过@Component注册到spring容器里后,在这里注册到spring的事件广播器里
  7. String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
  8. for (String listenerBeanName : listenerBeanNames) {
  9. getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
  10. }
  11. Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
  12. this.earlyApplicationEvents = null;
  13. if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
  14. for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
  15. getApplicationEventMulticaster().multicastEvent(earlyEvent);
  16. }
  17. }
  18. }

2.3事件发布器发布事件后,发生了什么?是怎么执行的监听器的回调方法了呢?

顺着UserService#registe()里的this.applicationEventPublisher.publishEvent(),使劲往里面找,最后找到了AbstractApplicationContext#publishEvent(java.lang.Object),到这感觉出来点啥没,所有的逻辑都指向AbstractApplicationContext类,这里先按下不表,继续往下找事件是发布到哪了,最后在AbstractApplicationContext#publishEvent(Object, ResolvableType)里找到了一句 getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType),顺着getApplicationEventMulticaster(),再往下找到spring的事件广播器接口ApplicationEventMulticaster,SimpleApplicationEventMulticaster是ApplicationEventMulticaster接口的实现类,这下明白在第一个问题中疑问了吧,表面上的事件发布器是ApplicationEventPublisher,而实际最终执行发布事件的是SimpleApplicationEventMulticaster。

  1. protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
  2. Assert.notNull(event, "Event must not be null");
  3. // Decorate event as an ApplicationEvent if necessary
  4. ApplicationEvent applicationEvent;
  5. if (event instanceof ApplicationEvent) {
  6. applicationEvent = (ApplicationEvent) event;
  7. }
  8. else {
  9. applicationEvent = new PayloadApplicationEvent<>(this, event);
  10. if (eventType == null) {
  11. eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
  12. }
  13. }
  14. // Multicast right now if possible - or lazily once the multicaster is initialized
  15. if (this.earlyApplicationEvents != null) {
  16. this.earlyApplicationEvents.add(applicationEvent);
  17. }
  18. else {
  19. getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
  20. }
  21. // Publish event via parent context as well...
  22. if (this.parent != null) {
  23. if (this.parent instanceof AbstractApplicationContext) {
  24. ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
  25. }
  26. else {
  27. this.parent.publishEvent(event);
  28. }
  29. }
  30. }

到这里,只是找到了通过this.applicationEventPublisher.publishEvent()找到了发布事件的实际干活人(SimpleApplicationEventMulticaster),它是怎么干活的呢?

沉住气,继续向里面翻SimpleApplicationEventMulticaster#multicastEvent(ApplicationEvent, ResolvableType)后,仔细看一下里面的逻辑:先看一下有没有线程池可用,如果有,就用,如果没有,就不用,直接执行监听器里的回调方法onApplicationEvent(),最后找到了SmsListener中具体执行发短信操作的onApplicationEvent();

  1. public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
  2. ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
  3. Executor executor = getTaskExecutor();
  4. for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
  5. if (executor != null) {
  6. executor.execute(() -> invokeListener(listener, event));
  7. }
  8. else {
  9. invokeListener(listener, event);
  10. }
  11. }
  12. }

80a4d2f509ce48d19eb7e1b8db9c83f0.png

684c8cdb078242d685d981bbff1d0926.png

3.总结

Spring事件的发布器的实例化、Spring事件监听器注册到事件发布器、Spring事件的发布都指向一个类AbstractApplicationContext,其中Spring事件的发布器的实例化、Spring事件监听器注册到事件发布器都是在AbstractApplicationContext#refresh()里完成,了解spring bean的生命周期的小伙伴,对这个方法肯定不陌生,这可是spring容器启动的灵魂,因此玩好spring,bean的生命周期必须玩透。到这里spring事件监听机制的工作原理基本摸清楚了,很多关键的事情,如事件发布器的实例化、事件监听器的注册这些都在spring容器启动的时候就开始了。这些关系理清楚后,才突然发现:真的是大道至简,牛逼就是简单,简单就是牛逼,致敬spring!

35c90755b4c54986a71606fdb10f097e.png

发表评论

表情:
评论列表 (有 0 条评论,149人围观)

还没有评论,来说两句吧...

相关阅读

    相关 事件监听机制

    ![这里写图片描述][20160420164724788]   Java中的事件监听是整个Java消息传递的基础和关键。牵涉到三类对象:事件源(Event S