一、【问题】SpringBoot 监听器触发机制?

获得监听器列表流程

Start -> getApplicationListeners -> 是否缓存 -----> (否) --> retrieveApplicationListeners -> 遍历监听器 -> supportsEvent ----->是 -->加入符合条件监听器列表 --> end

 

通用触发条件

SpringBoot 监听器触发机制

 

 

 

以SpringApplicationRunListeners 为例。进入run方法

SpringBoot 监听器触发机制

 

 

进入starting方法。里面是遍历所有的SpringApplicationRunListeners 

SpringBoot 监听器触发机制

 

 

内部是调用一个广播器发送

SpringBoot 监听器触发机制

 

3、进入multicastEvent方法。然后进入resolveDefaultEventType 方法。resolveDefaultEventType方法是对event的包装,不需要过多关注。

SpringBoot 监听器触发机制

 

 

 

4) 然后进入multicastEvent方法

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

  


Executor executor = getTaskExecutor(); 获得线程池

getApplicationListeners(event, type) 获得对当前event感兴趣的监听器列表

 

5)getApplicationListeners(event, type) 获得对当前event感兴趣的监听器列表

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

  获得事件的来源Object source = event.getSource();

SpringBoot 监听器触发机制

 source就是SpringApplication

SpringBoot 监听器触发机制

 

 

如果已经在缓存中存在感兴趣的监听器,直接返回

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

  

 6、retrieveApplicationListeners(eventType, sourceType, retriever)方法

	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);
		}
		for (ApplicationListener<?> listener : listeners) {
			if (supportsEvent(listener, eventType, sourceType)) {
				if (retriever != null) {
					retriever.applicationListeners.add(listener);
				}
				allListeners.add(listener);
			}
		}
		if (!listenerBeans.isEmpty()) {
			BeanFactory beanFactory = getBeanFactory();
			for (String listenerBeanName : listenerBeans) {
				try {
					Class<?> listenerType = beanFactory.getType(listenerBeanName);
					if (listenerType == null || supportsEvent(listenerType, 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);
						}
					}
				}
				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;
	}

  

监听器列表如下图

SpringBoot 监听器触发机制

 

 这些监听器定义在SpringBoot中的spring.factories文件中

SpringBoot 监听器触发机制

 

只有对当前eventType感兴趣的listerer才会添加到监听器列表中

for (ApplicationListener<?> listener : listeners) {
			if (supportsEvent(listener, eventType, sourceType)) {
				if (retriever != null) {
					retriever.applicationListeners.add(listener);
				}
				allListeners.add(listener);
			}
		}

 

7、进入 supportsEvent方法

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

 

如果不是GenericApplicationListener,则实例GenericApplicationListener. 然后进入GenericApplicationListener构造函数

SpringBoot 监听器触发机制

 

resolveDeclaredEventType方法 计算感兴趣的事件类型。

 

进入smartListener.supportsEventType(eventType)

SpringBoot 监听器触发机制

 

 

this.delegate的值为ConfigFileApplicationListener。

SpringBoot 监听器触发机制

 

ConfigFileApplicationListener实现了SmartApplicationListener接口

 SpringBoot 监听器触发机制

 

 

8、进入invokeListener(listener, event)方法

SpringBoot 监听器触发机制

 

 

SpringBoot 监听器触发机制

 

 


 

二、将前面的天气监听器在Test类调用改造成SpringBoot的形式

1、原来的Test类

SpringBoot 监听器触发机制

 

 

2、监听器部分

1) 增加WeatherRunListener

SpringBoot 监听器触发机制

 

 

2)、下雨监听器增加Component

SpringBoot 监听器触发机制

 

 

3)下雪监听器增加Component

SpringBoot 监听器触发机制

 

 4) 增加单元测试

SpringBoot 监听器触发机制

 

 5) 查看运行效果

SpringBoot 监听器触发机制

 

相关文章:

  • 2022-12-23
  • 2021-10-30
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-05-24
  • 2021-06-05
  • 2021-08-03
  • 2021-09-26
  • 2022-12-23
  • 2021-06-30
  • 2022-12-23
相关资源
相似解决方案