发布订阅(观察者)模式之Spring源码ApplicationListener解析

8 篇文章 0 订阅
3 篇文章 0 订阅

发布订阅模式之Spring源码ApplicationListener解析

  • 在之前的博客中有介绍过发布订阅模式, 也就是观察者模式, 想要了解的同学可以看我博客https://editor.csdn.net/md/?articleId=126689739

  • 他的uml图如下(图一)

  • 在这里插入图片描述

  • 这里我们在重点讲一下发布订阅模式在spring源码中的应用

  • 为了大家有一个整体的认识, 我先把主要涉及到的类先画出uml, 如下

  • 在这里插入图片描述

  • 接下来我们来分析一下源码

  • ApplicationListener作为观察者, 定义onApplicationEvent。 对应图一的Observer

    •   public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
        
        	/**
        	 * Handle an application event.
        	 * @param event the event to respond to
        	 */
        	void onApplicationEvent(E event);
        
        }
      
  • 事件的发布, 是通过ApplicationContext 的publishEvent , 他的默认实现是接口ApplicationEventPublisher, 所以 ApplicationContext 就作为观察目标(图一的Subject)

    •   public interface ApplicationEventPublisher {
        
        	/**
        	 * Notify all <strong>matching</strong> listeners registered with this
        	 * application of an application event. Events may be framework events
        	 * (such as RequestHandledEvent) or application-specific events.
        	 * @param event the event to publish
        	 * @see org.springframework.web.context.support.RequestHandledEvent
        	 */
        	default void publishEvent(ApplicationEvent event) {
        		publishEvent((Object) event);
        	}
        
        	/**
        	 * Notify all <strong>matching</strong> listeners registered with this
        	 * application of an event.
        	 * <p>If the specified {@code event} is not an {@link ApplicationEvent},
        	 * it is wrapped in a {@link PayloadApplicationEvent}.
        	 * @param event the event to publish
        	 * @since 4.2
        	 * @see PayloadApplicationEvent
        	 */
        	void publishEvent(Object event);
        
        }
      
  • 我们再看一下实现细节, 可以找到AbstractApplicationContext, 代码片段如下

    •   	protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
        		Assert.notNull(event, "Event must not be null");
        		if (logger.isTraceEnabled()) {
        			logger.trace("Publishing event in " + getDisplayName() + ": " + event);
        		}
        
        		// 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);这是他的具体实现, 可以定位到org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent, 代码如下, 也是用for循环去便利观察者, 参考图一中的for

      •   	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
          		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
          		for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
          			Executor executor = getTaskExecutor();
          			if (executor != null) {
          				executor.execute(() -> invokeListener(listener, event));
          			}
          			else {
          				invokeListener(listener, event);
          			}
          		}
          	}
        
      • 最后我们看一下invokeListener的实现, doInvokeListener, 可以发现, 是调用了观察者ApplicationListener的onApplicationEvent方法

        •   	private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
            		try {
            			listener.onApplicationEvent(event);
            		}
            		catch (ClassCastException ex) {
            			String msg = ex.getMessage();
            			if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
            				// Possibly a lambda-defined listener which we could not resolve the generic event type for
            				// -> let's suppress the exception and just log a debug message.
            				Log logger = LogFactory.getLog(getClass());
            				if (logger.isDebugEnabled()) {
            					logger.debug("Non-matching event type for listener: " + listener, ex);
            				}
            			}
            			else {
            				throw ex;
            			}
            		}
            	}
          
    • 到这里你是不是已近明白了尼

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BinBin_Bang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值