SpringBoot 源码解析4:事件监听器

SpringBoot 源码解析4:事件监听器

1. 初始化监听器

SpringBoot启动需要环境配置,在这个步骤之前Spring容器并没有刷新,无法获取自定义的监听器。所以在SpringApplication的构造器中,在spring.factories文件中定义了监听器。当然用户也能通过@Component定义监听器监听ApplicationStartedEvent事件。

java 复制代码
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
	this.resourceLoader = resourceLoader;
	Assert.notNull(primarySources, "PrimarySources must not be null");
	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
	this.webApplicationType = WebApplicationType.deduceFromClasspath();
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	this.mainApplicationClass = deduceMainApplicationClass();
}

在创建SpringApplication构造器的时候,通过ApplicationListener类名对应的key获取到监听器的类名,并且实例化,保存到SprngApplication.listeners

2. 创建事件发布器 SpringApplicationRunListeners

在SpringApplication#run方法中,获取到了SpringApplicationRunListeners,并且对不同的事件进行了分发。

java 复制代码
//SpringApplication#getRunListeners
private SpringApplicationRunListeners getRunListeners(String[] args) {
	Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
	return new SpringApplicationRunListeners(logger,
			getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}

//EventPublishingRunListener#EventPublishingRunListener
public EventPublishingRunListener(SpringApplication application, String[] args) {
	this.application = application;
	this.args = args;
	this.initialMulticaster = new SimpleApplicationEventMulticaster();
	for (ApplicationListener<?> listener : application.getListeners()) {
		this.initialMulticaster.addApplicationListener(listener);
	}
}

//AbstractApplicationEventMulticaster#addApplicationListener
public void addApplicationListener(ApplicationListener<?> listener) {
	synchronized (this.retrievalMutex) {
		// Explicitly remove target for a proxy, if registered already,
		// in order to avoid double invocations of the same listener.
		Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
		if (singletonTarget instanceof ApplicationListener) {
			this.defaultRetriever.applicationListeners.remove(singletonTarget);
		}
		this.defaultRetriever.applicationListeners.add(listener);
		this.retrieverCache.clear();
	}
}

实例化SpringApplicationRunListener对应的类名,也就是EventPublishingRunListener。其实真正负责事件发布的是initialMulticaster(SimpleApplicationEventMulticaster),从springApplication中拿到已经初始化完毕的监听器,放入到initialMulticaster,以便回调监听器。

java 复制代码
	void starting() {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.starting();
		}
	}

	void environmentPrepared(ConfigurableEnvironment environment) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.environmentPrepared(environment);
		}
	}

	void contextPrepared(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.contextPrepared(context);
		}
	}

	void contextLoaded(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.contextLoaded(context);
		}
	}

	void started(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.started(context);
		}
	}

	void running(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.running(context);
		}
	}

	void failed(ConfigurableApplicationContext context, Throwable exception) {
		for (SpringApplicationRunListener listener : this.listeners) {
			callFailedListener(listener, context, exception);
		}
	}

可以看到,SpringApplicationRunListeners中分发了很多事件,我们就拿environmentPrepared举例。

3. 事件分发流程

3.1 SimpleApplicationEventMulticaster#multicastEvent

java 复制代码
@Override
public void multicastEvent(ApplicationEvent event) {
	multicastEvent(event, resolveDefaultEventType(event));
}

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
	ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
	Executor executor = getTaskExecutor();
	for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
		if (executor != null) {
			executor.execute(() -> invokeListener(listener, event));
		}
		else {
			invokeListener(listener, event);
		}
	}
}

//回调监听器
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.isTraceEnabled()) {
				logger.trace("Non-matching event type for listener: " + listener, ex);
			}
		}
		else {
			throw ex;
		}
	}
}
  1. 解析事件的类型。
  2. 获取到监听器,这里需要通过不同的事件类型去匹配,不同的监听器处理不同的事件。
  3. 这里可配置线程池执行器Executor,如果有Executor,那么就通过线程的方式去回调监听器onApplicationEvent方法

3.2 获取监听器 AbstractApplicationEventMulticaster#getApplicationListeners

java 复制代码
protected Collection<ApplicationListener<?>> getApplicationListeners(
		ApplicationEvent event, ResolvableType eventType) {

	Object source = event.getSource();
	Class<?> sourceType = (source != null ? source.getClass() : null);
	ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);

	// Quick check for existing entry on ConcurrentHashMap...
	ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
	if (retriever != null) {
		return retriever.getApplicationListeners();
	}

	if (this.beanClassLoader == null ||
			(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
					(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
		// Fully synchronized building and caching of a ListenerRetriever
		synchronized (this.retrievalMutex) {
			retriever = this.retrieverCache.get(cacheKey);
			if (retriever != null) {
				return retriever.getApplicationListeners();
			}
			retriever = new ListenerRetriever(true);
			Collection<ApplicationListener<?>> listeners =
					retrieveApplicationListeners(eventType, sourceType, retriever);
			this.retrieverCache.put(cacheKey, retriever);
			return listeners;
		}
	}
	else {
		// No ListenerRetriever caching -> no synchronization necessary
		return retrieveApplicationListeners(eventType, sourceType, null);
	}
}

先从缓存中获取,缓存有,就直接返回;缓存没有,就通过retrieveApplicationListeners返回监听器。缓存key为事件类型ApplicationEnvironmentPreparedEvent和springApplication。

3.3 AbstractApplicationEventMulticaster#retrieveApplicationListeners

java 复制代码
private Collection<ApplicationListener<?>> retrieveApplicationListeners(
		ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {

	List<ApplicationListener<?>> allListeners = new ArrayList<>();
	Set<ApplicationListener<?>> listeners;
	Set<String> listenerBeans;
	synchronized (this.retrievalMutex) {
		listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
		listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
	}

	// Add programmatically registered listeners, including ones coming
	// from ApplicationListenerDetector (singleton beans and inner beans).
	for (ApplicationListener<?> listener : listeners) {
		if (supportsEvent(listener, eventType, sourceType)) {
			if (retriever != null) {
				retriever.applicationListeners.add(listener);
			}
			allListeners.add(listener);
		}
	}

	// Add listeners by bean name, potentially overlapping with programmatically
	// registered listeners above - but here potentially with additional metadata.
	if (!listenerBeans.isEmpty()) {
		ConfigurableBeanFactory beanFactory = getBeanFactory();
		for (String listenerBeanName : listenerBeans) {
			try {
				if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
					ApplicationListener<?> listener =
							beanFactory.getBean(listenerBeanName, ApplicationListener.class);
					if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
						if (retriever != null) {
							if (beanFactory.isSingleton(listenerBeanName)) {
								retriever.applicationListeners.add(listener);
							}
							else {
								retriever.applicationListenerBeans.add(listenerBeanName);
							}
						}
						allListeners.add(listener);
					}
				}
				else {
					// Remove non-matching listeners that originally came from
					// ApplicationListenerDetector, possibly ruled out by additional
					// BeanDefinition metadata (e.g. factory method generics) above.
					Object listener = beanFactory.getSingleton(listenerBeanName);
					if (retriever != null) {
						retriever.applicationListeners.remove(listener);
					}
					allListeners.remove(listener);
				}
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Singleton listener instance (without backing bean definition) disappeared -
				// probably in the middle of the destruction phase
			}
		}
	}

	AnnotationAwareOrderComparator.sort(allListeners);
	if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
		retriever.applicationListeners.clear();
		retriever.applicationListeners.addAll(allListeners);
	}
	return allListeners;
}
  1. 循环所有的listeners,调用supportsEvent方法判断listener是否支持当前的事件,支持就放入retriever里面。
  2. listenerBeans原理一样,只是从Spring容器中拿到所属的bean而已。

3.4 AbstractApplicationEventMulticaster#supportsEvent

这是真正判断事件与监听器匹配关系的方法

java 复制代码
protected boolean supportsEvent(
		ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {

	GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
			(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
	return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
  1. 当前的监听器是否属于GenericApplicationListener 类型,不是就包装成GenericApplicationListenerAdapter。
java 复制代码
public GenericApplicationListenerAdapter(ApplicationListener<?> delegate) {
	Assert.notNull(delegate, "Delegate listener must not be null");
	this.delegate = (ApplicationListener<ApplicationEvent>) delegate;
	this.declaredEventType = resolveDeclaredEventType(this.delegate);
}
//resolveDeclaredEventType 解析监听器中声明的泛型类型
@Nullable
private static ResolvableType resolveDeclaredEventType(ApplicationListener<ApplicationEvent> listener) {
	ResolvableType declaredEventType = resolveDeclaredEventType(listener.getClass());
	if (declaredEventType == null || declaredEventType.isAssignableFrom(ApplicationEvent.class)) {
		Class<?> targetClass = AopUtils.getTargetClass(listener);
		if (targetClass != listener.getClass()) {
			declaredEventType = resolveDeclaredEventType(targetClass);
		}
	}
	return declaredEventType;
}

@Nullable
static ResolvableType resolveDeclaredEventType(Class<?> listenerType) {
	ResolvableType eventType = eventTypeCache.get(listenerType);
	if (eventType == null) {
		eventType = ResolvableType.forClass(listenerType).as(ApplicationListener.class).getGeneric();
		eventTypeCache.put(listenerType, eventType);
	}
	return (eventType != ResolvableType.NONE ? eventType : null);
}

值得注意的是,在GenericApplicationListenerAdapter构造器中,resolveDeclaredEventType方法解析了监听器中声明的泛型。方便后面将监听器中声明的泛型与事件的类型进行对比,如果支持,就说明这个监听器需要被回调。

  1. 判断监听器会否支持类型,并且监听器是否支持sourceType,也就是springApplication,默认支持。
java 复制代码
public boolean supportsEventType(ResolvableType eventType) {
	if (this.delegate instanceof SmartApplicationListener) {
		Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.resolve();
		return (eventClass != null && ((SmartApplicationListener) this.delegate).supportsEventType(eventClass));
	}
	else {
		return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
	}
}
  1. 获取到事件所对应的监听器已结束,回调监听器。
相关推荐
Chrikk16 分钟前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*19 分钟前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue20 分钟前
go语言连续监控事件并回调处理
开发语言·后端·golang
杜杜的man22 分钟前
【go从零单排】go语言中的指针
开发语言·后端·golang
测开小菜鸟23 分钟前
使用python向钉钉群聊发送消息
java·python·钉钉
P.H. Infinity1 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天1 小时前
java的threadlocal为何内存泄漏
java
caridle2 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
^velpro^2 小时前
数据库连接池的创建
java·开发语言·数据库
苹果醋32 小时前
Java8->Java19的初步探索
java·运维·spring boot·mysql·nginx