SpringBoot源码解析 事件分发(Event)机制实现

提示: 此源码解析基于Spring Boot 2.1.1以及Spring Framework 5.1.3版本。
由于笔者做Web开发居多,因此在详细解析之前先上个AnnotationConfigServletWebServerApplicationContext的类图吧。它是ApplicationContext在web环境下的默认实现。
AnnotationConfigServletWebServerApplicationContext 类图
Spring Boot官方文本档中关于events和listeners中可以看到这么一段描述。

Some events are actually triggered before the ApplicationContext is created, so you cannot register a listener on those as a @Bean. You can register them with the SpringApplication.addListeners(…​) method or the SpringApplicationBuilder.listeners(…​) method.

这段解释很直白,我这边就不做翻译了,结合代码之后得出一个结论:Spring Boot事件的分发其实分两个阶段。

  • ApplicationContext尚未完成refresh时,Spring Boot使用EventPublishingRunListener进行事件分发。
    SpringApplicationrun(String... args)中,可以看到这么一行,
public ConfigurableApplicationContext run(String... args) {
	xxx
	//创建分发器  提供启动过程中各种事件的分发
	SpringApplicationRunListeners listeners = getRunListeners(args);
	xxx
}

具体实现如下:

/**
  * 创建run()方法 监听器
  * 通过SrpingFactory获取实例  进行初始化完成前事件推送
  * 默认实现为{@link org.springframework.boot.context.event.EventPublishingRunListener}
  * called by {@link #run(String...)}
  * @param args
  * @return
  */
 private SpringApplicationRunListeners getRunListeners(String[] args) {
 	Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
 	return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
 }

SpringApplicationRunListener的唯一实现正是EventPublishingRunListener,来看下它的注释。

/**
 * 此Class用于在context被完全初始化之前传递消息。
 * 在初始化完成之前,Srping默认的消息分发器{@link SpringApplicationRunListener}并不可用。
 * 此分发器传递的任何消息不会被用户自定义的监听器监听到。
 * {@link SpringApplicationRunListener} to publish {@link SpringApplicationEvent}s.
 * <p>
 * Uses an internal {@link ApplicationEventMulticaster} for the events that are fired
 * before the context is actually refreshed.
 *
 * @author Phillip Webb
 * @author Stephane Nicoll
 * @author Andy Wilkinson
 * @author Artsiom Yudovin
 */
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered 

其实也很容易理解,在这个阶段,Spring Boot尚未初始化Spring FrameWork的组件,自然没有办法使用Spring FrameWork的事件分发机制,因此只能自己实现事件分发来进行启动阶段的代码解耦。

  • 完全启动后,使用Spring FrameWork的事件分发机制。
    在环境准备完成后,SpringApplication会调用refresh这个方法。可以看的出来,其实调用的是父类AbstractApplicationContext的方法,此方法中进行了大量组件的初始化,其中就有我们需要的initApplicationEventMulticaster
/**
	 * 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() + "]");
			}
		}
	}

可以看到其默认实现为SimpleApplicationEventMulticaster,也是EventPublishingRunListener的父类。
Ok,到此为止,事件分发器的初始化暂时是搞清楚了。
那么我们在调用publishEvent()方法时到底发生了什么呢?
观察类图可以得知ApplicationContext是继承了ApplicationEventPublisher接口的。

/**
 * Interface that encapsulates event publication functionality.
 * Serves as super-interface for {@link ApplicationContext}.
 *
 * @author Juergen Hoeller
 * @author Stephane Nicoll
 * @since 1.1.1
 * @see ApplicationContext
 * @see ApplicationEventPublisherAware
 * @see org.springframework.context.ApplicationEvent
 * @see org.springframework.context.event.EventPublicationInterceptor
 */
@FunctionalInterface
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);

}

接口定义找到了,那么其实现是在哪里呢?
由于SpringApplication的run方法直接返回的ConfigurableApplicationContext是可以直接推送事件的,因此我们直接按照类图从它的子类中找就好了,还是熟悉的AbstractApplicationContext
好的,柳暗花明之后,终于可以观察以下真正的推送逻辑了。

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

在这里可以看到其使用的事件分发器确实是SimpleApplicationEventMulticaster,进而调用了multicastEvent方法进而完成事件分发。

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

注意: 从代码可以看到ApplicationListener是支持异步执行的,否则的话就会使用单一线程循环推送。如果某个ApplicationListener耗时过长是会导致推送延迟的。因此为了性能考虑最好还是使用线程池。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Qt 事件循环机制是 Qt 框架的核心,它负责处理所有的事件和信号槽机制。Qt 事件循环机制源码实现比较复杂,涉及到多个类和文件。下面是一个简单的 Qt 事件循环机制源码解析: 1. 事件循环机制的入口函数是 QCoreApplication::exec(),它是一个静态函数,会启动事件循环。 2. 在事件循环中,Qt 会不断地从事件队列中取出事件,然后分发给对应的对象处理。事件队列是一个双向链表,由 QEventDispatcherWin32(Windows 平台)或 QEventDispatcherUNIX(Unix/Linux 平台)管理。 3. 事件分发的过程是通过 QObject::event() 函数实现的。当一个事件分发给一个对象时,它会首先调用对象的 event() 函数,如果该函数返回 false,那么事件会被传递给对象的父对象,直到有一个对象的 event() 函数返回 true,或者事件传递到了根对象。 4. 信号槽机制实现也依赖于事件循环机制。当一个信号被发射时,它会被转化为一个事件,然后被插入到事件队列中。当事件循环处理到该事件时,它会调用对应的槽函数。 5. 事件循环还涉及到消息循环和定时器机制。消息循环通过 QSocketNotifier 和 QAbstractEventDispatcher 类实现,它可以监听文件描述符和套接字等事件。定时器机制通过 QTimer 类实现,它可以定时触发事件。 总之,Qt 事件循环机制源码实现非常复杂,但它是 Qt 框架的核心,负责处理所有的事件和信号槽机制,是 Qt 能够高效运行的关键。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值