spring--监听器(listener)原理解析

spring的监听器(listener)原理解析

首先看一下如何使用listener

  • 编写事件源(Event)

    import org.springframework.context.ApplicationEvent;
    
    public class TestEvent extends ApplicationEvent {
    
        public TestEvent(Object obj) {
            super(obj);
        }
    }
    
  • 编写事件监听器(listener)

    import org.springframework.context.ApplicationListener;
    import org.springframework.stereotype.Component;
    
    @Component
    public class TestListener implements ApplicationListener<TestEvent> {
    
        @Override
        public void onApplicationEvent(TestEvent testEvent) {
            System.out.println(testEvent.getSource());
        }
    }
    
  • 编写测试用例

    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.context.ApplicationEventPublisher;
    import org.springframework.test.context.junit4.SpringRunner;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class ListenerTest {
    
        @Autowired
        private ApplicationEventPublisher applicationEventPublisher;
    
        @Test
        public void test() {
            TestEvent testEvent = new TestEvent("hello word");
            applicationEventPublisher.publishEvent(testEvent);
        }
    }
    
  • 执行日志

      .   ____          _            __ _ _
     /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
    ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
     \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
      '  |____| .__|_| |_|_| |_\__, | / / / /
     =========|_|==============|___/=/_/_/_/
     :: Spring Boot ::        (v2.2.0.RELEASE)
    
    2020-05-26 09:30:20.113  INFO 10760 --- [           main] com.example.demo.listener.ListenerTest   : Starting ListenerTest on PC with PID 10760 (started by ASUS in E:\workspace\demo)
    2020-05-26 09:30:20.115  INFO 10760 --- [           main] com.example.demo.listener.ListenerTest   : No active profile set, falling back to default profiles: default
    2020-05-26 09:30:20.568  INFO 10760 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
    2020-05-26 09:30:20.572  INFO 10760 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode.
    2020-05-26 09:30:20.613  INFO 10760 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 21ms. Found 0 repository interfaces.
    2020-05-26 09:30:21.714  INFO 10760 --- [           main] com.example.demo.listener.ListenerTest   : Started ListenerTest in 2.261 seconds (JVM running for 3.634)
    
    hello word
    
    
    
    Process finished with exit code 0
    

源码解析-加载监听器

  • 这个是在创建applicationContext过程中,从抽象类AbstractApplicationContextrefresh方法开始,去除注释和日志,我们来看看源码

    @Override
    public void refresh() throws BeansException, IllegalStateException {
    	synchronized (this.startupShutdownMonitor) {
    		
    		prepareRefresh();
    		
    		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    		
    		prepareBeanFactory(beanFactory);
    
    		try {
    			postProcessBeanFactory(beanFactory);
    			
    			invokeBeanFactoryPostProcessors(beanFactory);
    			
    			registerBeanPostProcessors(beanFactory);
    			
    			initMessageSource();
    			// 初始化一个广播器,之后注册监听器和发布事件都基于该广播器执行
    			initApplicationEventMulticaster();
    			
    			onRefresh();
    			// 注册监听器到广播器中
    			registerListeners();
    			
    			finishBeanFactoryInitialization(beanFactory);
    	
    			finishRefresh();
    		} catch (BeansException ex) {
    			
    			destroyBeans();
    			
    			cancelRefresh(ex);
    			
    			throw ex;
    		} finally {
    			resetCommonCaches();
    		}
    	}
    }
    
  • 这里我们只关心两个方法initApplicationEventMulticasterregisterListeners

  • initApplicationEventMulticaster();

    protected void initApplicationEventMulticaster() {
    	// 获取bean工厂
    	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    	// 判断是否存在applicationEventMulticaster这个bean
    	if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
    		// 如果存在则实例化这个bean并保存到applicationEventMulticaster
    		this.applicationEventMulticaster =
    				beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
    	}
    	else {
    		// 否则创建一个广播器并注册单例到bean工厂
    		this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
    		beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
    	}
    }
    
  • registerListeners();

    protected void registerListeners() {
    	// Register statically specified listeners first--这是官方的注释,指通过硬编码添加的监听器
    	for (ApplicationListener<?> listener : getApplicationListeners()) {
    		getApplicationEventMulticaster().addApplicationListener(listener);
    	}
    	// 从bean工厂获取所有实现了ApplicationListener接口的bean
    	String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    	for (String listenerBeanName : listenerBeanNames) {
    		getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    	}
    
    	// 预处理方法(prepareRefresh)之后,注册监听器方法(registerListeners)之前,发布的广播/事件(publishEvent)的都会缓存在这里进行统一发布,相当于创建应用上下文时的延迟广播
    	// multicastEvent方法具体实现放在发布过程详解
    	Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    	this.earlyApplicationEvents = null;
    	if (earlyEventsToProcess != null) {
    		for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
    			getApplicationEventMulticaster().multicastEvent(earlyEvent);
    		}
    	}
    }
    
  • 这里解释一下通过硬编码添加的监听器的意思

    1、新增MyAnnotationConfigApplicationContext类继承AnnotationConfigApplicationContext类重写onRefresh方法添加监听器

    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class MyAnnotationConfigApplicationContext extends AnnotationConfigApplicationContext {
    
        @Override
        protected void onRefresh() {
        	// 硬编码添加监听器
            this.addApplicationListener(new TestListener());
        }
    }
    

    2、 启动类增加springApplication.setApplicationContextClass(MyAnnotationConfigApplicationContext.class);

    import com.example.demo.listener.MyAnnotationConfigApplicationContext;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class DemoApplication {
    
        public static void main(String[] args) {
            SpringApplication springApplication = new SpringApplication(DemoApplication.class);
            springApplication.setApplicationContextClass(MyAnnotationConfigApplicationContext.class);
            springApplication.run(args);
        }
    }
    

    3、 这样就可以通过硬编码方式添加监听器了

  • 添加监听器到applicationListenersapplicationListeners集合

    public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
    	
    @Override
    public void addApplicationListener(ApplicationListener<?> listener) {
    	synchronized (this.retrievalMutex) {
    		// 获取代理对象
    		Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
    		// 避免重复添加监听器
    		if (singletonTarget instanceof ApplicationListener) {
    			this.defaultRetriever.applicationListeners.remove(singletonTarget);
    		}
    		this.defaultRetriever.applicationListeners.add(listener);
    		this.retrieverCache.clear();
    	}
    }
    
    public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
    
    @Override
    public void addApplicationListenerBean(String listenerBeanName) {
    	synchronized (this.retrievalMutex) {
    		this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);
    		this.retrieverCache.clear();
    	}
    }
    
  • 至此监听器已经全部注册完毕,都是基于initApplicationEventMulticaster方法生成的广播器进行注册,同时可以看到发布也是基于这个广播器发布的(multicastEvent方法)

源码解析-发布(publishEvent)方法

  • 接口ApplicationEventPublisher最终还是调用的实现类AbstractApplicationContextpublishEvent方法

    @FunctionalInterface
    public interface ApplicationEventPublisher {
    
    	
    	default void publishEvent(ApplicationEvent event) {
    		publishEvent((Object) event);
    	}
    
    	void publishEvent(Object event);
    
    }
    
    @Override
    public void publishEvent(ApplicationEvent event) {
    	publishEvent(event, null);
    }
    
    protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    	Assert.notNull(event, "Event must not be null");
    
    	// 判断事件源是否实现了ApplicationEvent接口并进行转化
    	ApplicationEvent applicationEvent;
    	if (event instanceof ApplicationEvent) {
    		applicationEvent = (ApplicationEvent) event;
    	}
    	else {
    		// 如果没有也要封装成ApplicationEvent事件
    		applicationEvent = new PayloadApplicationEvent<>(this, event);
    		if (eventType == null) {
    			eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
    		}
    	}
    
    	// 在初始化应用上下文预处理方法(prepareRefresh)之后,注册监听器方法(registerListeners)之前,这期间的发布全部进行延迟发布,交由registerListeners方法统一发布
    	// 此时earlyApplicationEvents为null
    	if (this.earlyApplicationEvents != null) {
    		this.earlyApplicationEvents.add(applicationEvent);
    	}
    	else {
    		// 获取广播器并发布事件
    		getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    	}
    
    	// 通过父上下文发布事件
    	if (this.parent != null) {
    		if (this.parent instanceof AbstractApplicationContext) {
    			((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
    		}
    		else {
    			this.parent.publishEvent(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);
    		}
    	}
    }
    
    protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
    	// 获取事件的源
    	Object source = event.getSource();
    	// 事件源的类型
    	Class<?> sourceType = (source != null ? source.getClass() : null);
    	// 一个简单类,当做map的key使用,用以区分不同的事件类型并设置缓存
    	ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
    
    	// 尝试从缓存获取
    	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 {
    		// 通过事件源查找符合的监听器
    		return retrieveApplicationListeners(eventType, sourceType, null);
    	}
    }
    
  • 最终是通过retrieveApplicationListeners方法进行监听器查找的

    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) {
    		// 获取前面注册监听器方法(registerListeners)注册的监听器
    		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);
    		}
    	}
    
    	// 解析通过实现ApplicationListener接口的监听器
    	if (!listenerBeans.isEmpty()) {
    		// 获取bean工厂
    		ConfigurableBeanFactory beanFactory = getBeanFactory();
    		for (String listenerBeanName : listenerBeans) {
    			try {
    				// 判断是否符合监听器
    				if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
    					// 通过bean工厂获取监听器
    					ApplicationListener<?> listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
    
    					// 如果不存在结果集中并且符合需要感知的监听器
    					if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
    						// 如果需要缓存
    						if (retriever != null) {
    							// 如果是单例,则添加监听器到缓存,否则添加beanName缓存
    							if (beanFactory.isSingleton(listenerBeanName)) {
    								retriever.applicationListeners.add(listener);
    							}
    							else {
    								retriever.applicationListenerBeans.add(listenerBeanName);
    							}
    						}
    						// 添加到查找到的监听器中
    						allListeners.add(listener);
    					}
    				}
    				else {
    					// 删除不符合感知的监听器需要移除对应的缓存和监听器结果
    					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
    			}
    		}
    	}
    
    	// 对监听器排序,如果存在@Order注解
    	AnnotationAwareOrderComparator.sort(allListeners);
    	// 如果applicationListenerBeans为空说明监听器全部在allListeners里,则清空applicationListeners重新添加即可
    	// applicationListenerBeans为空说明没有非单例bean
    	if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
    		retriever.applicationListeners.clear();
    		retriever.applicationListeners.addAll(allListeners);
    	}
    	// 反正最终查找到的监听器
    	return allListeners;
    }
    
  • 至此所有匹配的监听器已经找到,至于如何判断是否符合监听器的各位看官有兴趣可以自行了解,最后我们看看发布方法invokeListener

    protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
    	// 获取异常处理(默认为空,可以手动设置异常处理类)
    	ErrorHandler errorHandler = getErrorHandler();
    	if (errorHandler != null) {
    		try {
    			// 如果存在异常处理类,则在异常处理类内进行发布通知
    			doInvokeListener(listener, event);
    		}
    		catch (Throwable err) {
    			errorHandler.handleError(err);
    		}
    	}
    	else {
    		// 否则直接发布通知
    		doInvokeListener(listener, event);
    	}
    }
    
    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
    	try {
    		// 调用实现类的onApplicationEvent方法
    		listener.onApplicationEvent(event);
    	}
    	catch (ClassCastException ex) {
    		String msg = ex.getMessage();
    		if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
    			Log logger = LogFactory.getLog(getClass());
    			if (logger.isTraceEnabled()) {
    				logger.trace("Non-matching event type for listener: " + listener, ex);
    			}
    		}
    		else {
    			throw ex;
    		}
    	}
    }
    
  • 到这里所有方法解析就结束了

总结

  • 通过阅读源码,我们知道除了基础的应用,spring还为我们提供了哪些功能
    1、自己编写一个类实现ApplicationEventMulticaster接口代替默认的SimpleApplicationEventMulticaster广播器
    2、通过调用setTaskExecutor(@Nullable Executor taskExecutor)方法制定广播器的执行计划
    3、通过调用setErrorHandler(@Nullable ErrorHandler errorHandler)方法异常处理方案
    4、在监听器上添加@Order(int)注解制定监听器执行顺序
    5、期待留言补充。。。
  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值