spring boot源码-监听器

一,先自己实现两个监听器

1.实现ApplicationListener接口,泛型ApplicationStartingEvent,监听starting事件

@Order(1)
public class FirstListener implements ApplicationListener<ApplicationStartingEvent> {
    @Override
    public void onApplicationEvent(ApplicationStartingEvent event) {
        System.out.println("hello FirstListener");
    }
}

2.实现SmartApplicationListener接口,在supportsEventType方法中,去匹配需要监听的事件,此处监听starting,started,prepared事件

@Order(4)
public class FourthListener implements SmartApplicationListener {

    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
        return ApplicationStartingEvent.class.isAssignableFrom(eventType) ||ApplicationStartedEvent.class.isAssignableFrom(eventType) || ApplicationPreparedEvent.class.isAssignableFrom(eventType);
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("hello FourthListener");
    }
}

3.在resources/META-INF/spring.factories 中配置这两个类,key为接口,value为上述两个类,逗号隔开

#监听器配置
org.springframework.context.ApplicationListener=com.mooc.study.event.weather.listener.sb.FirstListener,com.mooc.study.event.weather.listener.sb.FourthListener

二.进入spring boot源码分析

1.分析starting事件,进入starting方法

2.跳转到广播器的广播事件方法multicastEvent

3.进入同名方法,调用getApplicationListeners方法,获取starting事件感兴趣的监听器

4.分析getApplicationListeners方法的源码,核心代码都写上注释,主要看注释

	/**
	 * Return a Collection of ApplicationListeners matching the given
	 * event type. Non-matching listeners get excluded early.
	 * @param event the event to be propagated. Allows for excluding
	 * non-matching listeners early, based on cached matching information.
	 * @param eventType the event type
	 * @return a Collection of ApplicationListeners
	 * @see org.springframework.context.ApplicationListener
	 */
	protected Collection<ApplicationListener<?>> getApplicationListeners(
			ApplicationEvent event, ResolvableType eventType) {
        //获取事件来源
		Object source = event.getSource();
        //监听的事件类型包装,此次是监听starting事件
		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);
                //核心方法,获取所有感兴趣的事件监听器(这一次是starting事件)
				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);
		}
	}

5.分析retrieveApplicationListeners方法源码,获取所有感兴趣的事件监听器(这一次是starting事件),重要代码全部写上注释

/**
 * Actually retrieve the application listeners for the given event and source type.
 * @param eventType the event type
 * @param sourceType the event source type
 * @param retriever the ListenerRetriever, if supposed to populate one (for caching purposes)
 * @return the pre-filtered list of application listeners for the given event and source type
 */
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);
		}
	}
	//根据order值进行排序
	AnnotationAwareOrderComparator.sort(allListeners);
	if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
		retriever.applicationListeners.clear();
		retriever.applicationListeners.addAll(allListeners);
	}
	return allListeners;
}

6.分析是否是感兴趣监听器方法supportsEvent(listener, eventType, sourceType)方法,回调监听器的supportsEventType方法    ,判断监听器是否对当前的事件感兴趣。如果是FourthListener这个自己实现的监听器则是回调如下方法进行判断

protected boolean supportsEvent(
		ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
	//判断是否是GenericApplicationListener的子类否则进行GenericApplicationListener包装
	GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
			(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
	//回调监听器的supportsEventType方法	,判断监听器是否对当前的事件感兴趣	
	return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}

7.最后广播器调用invokeListener(listener, event)方法进行事件执行

 

发布了10 篇原创文章 · 获赞 3 · 访问量 7621
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览