文章目录
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过程中,从抽象类AbstractApplicationContext的refresh方法开始,去除注释和日志,我们来看看源码
@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(); } } }
-
这里我们只关心两个方法initApplicationEventMulticaster和registerListeners
-
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、 这样就可以通过硬编码方式添加监听器了
-
添加监听器到applicationListeners和applicationListeners集合
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最终还是调用的实现类AbstractApplicationContext的publishEvent方法
@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、期待留言补充。。。