Spring事件执行流程源码分析

1. 背景

为啥突然想到写这个?起因就是看到了Nacos的#3757 ISSUE,理解错误, 以为是服务启动,没有注册上服务,实际namespace不同,导致服务无法注册。 但这丝毫不影响再去研究了一波代码,顺便也看到了Nacos是如何利用Spring的事件来进行服务注册的。分享一波,欢迎大家学习指正!

2. 娓娓道来 - Spring事件

2.1 怎么发布事件

我们大家应该都知道,在Spring中,是通过实现org.springframework.context.ApplicationEventPublisher来发布一个事件。ApplicationEcentPublisher是一个接口,我们来看一下接口中逻辑。

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

接口很简单,里面有两个方法,都是发布事件,而接口默认实现,是调用publishEvent(Object event)的实现,唯一的区别就是default方法的参数是具体的事件类。

既然这是个接口,那一定有实现类,那么我们肯定是要进入实现类,快捷键,查看一下具体实现类。
在这里插入图片描述

我们通过实现类,可以看到,应该是从AbstractApplicationContext进去(其他Context都是实现类,凭感觉和代码提示,从第一个类进如代码)。

进去org.springframework.context.support.AbstractApplicationContext,我们直奔主题,查看是如何实现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 = (ApplicationEvent) event;
		}
		else {
   
      		// 将事件装饰成PayloadApplicationEvent,
			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) {
   
      		// 广播还未初始化完成,放入earlyApplicationEvents.
			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. 发布的时间通过getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);广播事件

通过代码可以知道,我们接下来的关

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值