zoukankan      html  css  js  c++  java
  • SpringBoot 监听器触发机制

    一、【问题】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) 查看运行效果

  • 相关阅读:
    并发编程(四)—— ThreadLocal源码分析及内存泄露预防
    并发编程(三)—— ReentrantLock的用法
    并发编程(二)—— CountDownLatch、CyclicBarrier和Semaphore
    并发编程(一)—— volatile关键字和 atomic包
    Java 多线程(四)—— 单例模式
    Java 多线程(三)—— 线程的生命周期及方法
    Java 多线程(二)—— 线程的同步
    星空雅梦
    星空雅梦
    星空雅梦
  • 原文地址:https://www.cnblogs.com/linlf03/p/12274452.html
Copyright © 2011-2022 走看看