一、【问题】SpringBoot 监听器触发机制?
获得监听器列表流程
Start -> getApplicationListeners -> 是否缓存 -----> (否) --> retrieveApplicationListeners -> 遍历监听器 -> supportsEvent ----->是 -->加入符合条件监听器列表 --> end
通用触发条件
以SpringApplicationRunListeners 为例。进入run方法
进入starting方法。里面是遍历所有的SpringApplicationRunListeners
内部是调用一个广播器发送
3、进入multicastEvent方法。然后进入resolveDefaultEventType 方法。resolveDefaultEventType方法是对event的包装,不需要过多关注。
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();
source就是SpringApplication
如果已经在缓存中存在感兴趣的监听器,直接返回
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中的spring.factories文件中
只有对当前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构造函数
resolveDeclaredEventType方法 计算感兴趣的事件类型。
进入smartListener.supportsEventType(eventType)
this.delegate的值为ConfigFileApplicationListener。
ConfigFileApplicationListener实现了SmartApplicationListener接口
8、进入invokeListener(listener, event)方法
二、将前面的天气监听器在Test类调用改造成SpringBoot的形式
1、原来的Test类
2、监听器部分
1) 增加WeatherRunListener
2)、下雨监听器增加Component
3)下雪监听器增加Component
4) 增加单元测试
5) 查看运行效果
作者:Work Hard Work Smart
出处:http://www.cnblogs.com/linlf03/
欢迎任何形式的转载,未经作者同意,请保留此段声明!