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


    发布订阅模式之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);
          
          }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
    • 事件的发布, 是通过ApplicationContext 的publishEvent , 他的默认实现是接口ApplicationEventPublisher, 所以 ApplicationContext 就作为观察目标(图一的Subject)

      •   public interface ApplicationEventPublisher {
          
          	/**
          	 * Notify all matching 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 matching listeners registered with this
          	 * application of an event.
          	 * 

        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); }

        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
    • 我们再看一下实现细节, 可以找到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);
          			}
          		}
          	}
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33
        • 34
        • 35
        • 36
      • 重点看 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);
            			}
            		}
            	}
          
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
          • 9
          • 10
          • 11
          • 12
        • 最后我们看一下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;
              			}
              		}
              	}
            
            • 1
            • 2
            • 3
            • 4
            • 5
            • 6
            • 7
            • 8
            • 9
            • 10
            • 11
            • 12
            • 13
            • 14
            • 15
            • 16
            • 17
            • 18
            • 19
      • 到这里你是不是已近明白了尼

  • 相关阅读:
    CMake教程-第 7 步:添加系统自省功能
    本人常用软件(工具)
    Hadoop3教程(三十五):(生产调优篇)HDFS小文件优化与MR集群简单压测
    Spark Streaming 整合 Flume
    整数转罗马数字-----题解报告
    ES7 集群模式新增账号密码认证
    《优化接口设计的思路》系列:第二篇—接口用户上下文的设计与实现
    【华为OD机试真题 python】 敏感字段加密【2022 Q4 | 100分】
    浅谈 Raft 分布式一致性协议|图解 Raft
    计算机毕业设计JavaWeb闲置服装交易平台(源码+系统+mysql数据库+lw文档)
  • 原文地址:https://blog.csdn.net/biubiubiubibibi/article/details/126690023