交流
商城
MCN
登入
注册
首页
提问
分享
讨论
建议
公告
动态
发表新帖
发表新帖
第3 章: ApplicationListener
分享
未结
0
906
李延
LV6
2021-05-20
悬赏:20积分
# 作用 在spring启动不同阶段时,触发不同事件。向各个监听器发送响应的事件,方便对在不同阶段干预springboot的启动。 # 初始化 在解析SpringApplication时,我们看到一共使用的3个不同的类,分别是:SpringApplicationRunListeners、SpringApplicationRunListener、ApplicationListener。 其中SpringApplicationRunListeners 是代码中直接new出来的,其他两个分别是通过读取META-INF/spring.factories文件加载出来的。下面我们分别解析这3个类,与其中的关系。 # SpringApplicationRunListeners 其实通过名字就可以看出来。是多个SpringApplicationRunListener的集合。其实它的作用就是通过调用一个SpringApplicationRunListeners的方法,就可以直接循环所以的SpringApplicationRunListener。 我们看到它的构造函数,就是接收多个SpringApplicationRunListener,将保存在成员变量中。 同时它的每个方法就是循环调用这个成员变量的所有元素。 # SpringApplicationRunListener ## 初始化 在SpringApplication中,我们看到是通过加载META-INF/spring.factories获取的SpringApplicationRunListener  在springboot中只有一个实现:EventPublishingRunListener。下面我们具体看一下EventPublishingRunListener的构造方法 ```java public EventPublishingRunListener(SpringApplication application, String[] args) { this.application = application; this.args = args; this.initialMulticaster = new SimpleApplicationEventMulticaster(); for (ApplicationListener<?> listener : application.getListeners()) { this.initialMulticaster.addApplicationListener(listener); } } ``` 我们看到首先是换取到application中所有的ApplicationListener对象。这个集合也是通过META-INF/spring.factories文件加载的,具体见:SpringApplication解析,并且创建SimpleApplicationEventMulticaster对象,并将listener对象添加。 而这个类的所有方法就是不同事件触发。基本上所有的事件实现基本一致,都是调用的initialMulticaster对象发送的事件。对于SimpleApplicationEventMulticaster代码解析放在本章节最后 ```java @Override public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) { this.initialMulticaster.multicastEvent( new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment)); } @Override public void contextPrepared(ConfigurableApplicationContext context) { this.initialMulticaster .multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context)); } ``` 上面为列举的部分代码。我们看到都是调用的initialMulticaster的multicastEvent方法。唯一不同就是不同方法会传入不同的参数,发送不同的事件。 所以下面我们主要以每个事件在何时触发,触发时,发送的是什么事件来进行解析。 ## starting 当前事件是在springboot最开始触发,此时springboot还未做任何事情。 此时发送的是:ApplicationStartingEvent 事件 ## environmentPrepared 当前事件是在springboot创建完成environment创建,并完成了基本的配置后触发的事件。 我们配置文件的加载就是在当前事件中进行加载的。 此时发送的是:ApplicationEnvironmentPreparedEvent 事件 ## contextPrepared 当前事件是在springboot创建完成context后,并完成基本配置后触发的事件。 此时发送的是:ApplicationContextInitializedEvent 事件 ## contextLoaded 当前事件是在context对象加载完成资源后,也就是加载完成我们参数传入的class对象后的事件。 此时发送的是:ApplicationPreparedEvent 事件 ## started context 刷新完成上下文后的事件。 此时发送的是:ApplicationStartedEvent 事件 ## running 启动完成后,进入运行状态后的事件。 此时发送的是:ApplicationReadyEvent 事件 # SimpleApplicationEventMulticaster 在上面分析过程中,我们知道所以的事件都通过当前类来进行发送事件的,下面我们具体解析一下事件是如何发送的。我们直接看发送事件的方法: ```java @Override public void multicastEvent(ApplicationEvent event) { multicastEvent(event, resolveDefaultEventType(event)); } ``` 首先是调用了resolveDefaultEventType方法,具体如下: ```java private ResolvableType resolveDefaultEventType(ApplicationEvent event) { return ResolvableType.forInstance(event); } ``` 其实就是通过对象直接获取其类型ResolvableType。 之后是调用了重载方法,具体如下: ```java @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 if (this.applicationStartup != null) { StartupStep invocationStep = this.applicationStartup.start("spring.event.invoke-listener"); invokeListener(listener, event); invocationStep.tag("event", event::toString); if (eventType != null) { invocationStep.tag("eventType", eventType::toString); } invocationStep.tag("listener", listener::toString); invocationStep.end(); } else { invokeListener(listener, event); } } } ``` 忽略掉额外的判断,我们发现主要有两个方法 1. 通过 getApplicationListeners(event, type) 获取到符合当前类型的监听器。 2. 循环第一步的结果调用invokeListener方法触发事件。 而其中invokeListener方法最终是通过调用监听器的onApplicationEvent方法发送事件的,就不在这里说明了。 我们将关注点放在getApplicationListeners上看看是如何筛选监听器的。 ```java 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); // Potential new retriever to populate CachedListenerRetriever newRetriever = null; // Quick check for existing entry on ConcurrentHashMap CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey); if (existingRetriever == null) { // Caching a new ListenerRetriever if possible if (this.beanClassLoader == null || (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) { newRetriever = new CachedListenerRetriever(); existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever); if (existingRetriever != null) { newRetriever = null; // no need to populate it in retrieveApplicationListeners } } } if (existingRetriever != null) { Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners(); if (result != null) { return result; } // If result is null, the existing retriever is not fully populated yet by another thread. // Proceed like caching wasn't possible for this current local attempt. } return retrieveApplicationListeners(eventType, sourceType, newRetriever); } ``` 我们看到首先判断retrieverCache 是否有缓存,而对于缓存的依据有2个条件: 1. sourceType 事件是从同一个源触发的,也就是同一个对象调用的。 2. eventType 发送的是同一个事件。 对于没有缓存的数据我们通过retrieveApplicationListeners方法进行筛选,我们解析跟进: ```java private Collection<ApplicationListener<?>> retrieveApplicationListeners( ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable CachedListenerRetriever retriever) { List<ApplicationListener<?>> allListeners = new ArrayList<>(); Set<ApplicationListener<?>> filteredListeners = (retriever != null ? new LinkedHashSet<>() : null); Set<String> filteredListenerBeans = (retriever != null ? new LinkedHashSet<>() : null); Set<ApplicationListener<?>> listeners; Set<String> listenerBeans; synchronized (this.defaultRetriever) { listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners); listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans); } // Add programmatically registered listeners, including ones coming // from ApplicationListenerDetector (singleton beans and inner beans). for (ApplicationListener<?> listener : listeners) { if (supportsEvent(listener, eventType, sourceType)) { if (retriever != null) { filteredListeners.add(listener); } allListeners.add(listener); } } // Add listeners by bean name, potentially overlapping with programmatically // registered listeners above - but here potentially with additional metadata. if (!listenerBeans.isEmpty()) { ConfigurableBeanFactory beanFactory = getBeanFactory(); for (String listenerBeanName : listenerBeans) { try { if (supportsEvent(beanFactory, listenerBeanName, eventType)) { ApplicationListener<?> listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class); if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) { if (retriever != null) { if (beanFactory.isSingleton(listenerBeanName)) { filteredListeners.add(listener); } else { filteredListenerBeans.add(listenerBeanName); } } allListeners.add(listener); } } else { // Remove non-matching listeners that originally came from // ApplicationListenerDetector, possibly ruled out by additional // BeanDefinition metadata (e.g. factory method generics) above. Object listener = beanFactory.getSingleton(listenerBeanName); if (retriever != null) { filteredListeners.remove(listener); } allListeners.remove(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) { if (filteredListenerBeans.isEmpty()) { retriever.applicationListeners = new LinkedHashSet<>(allListeners); retriever.applicationListenerBeans = filteredListenerBeans; } else { retriever.applicationListeners = filteredListeners; retriever.applicationListenerBeans = filteredListenerBeans; } } return allListeners; } ``` 上面的核心代码为: ```java for (ApplicationListener<?> listener : listeners) { if (supportsEvent(listener, eventType, sourceType)) { if (retriever != null) { filteredListeners.add(listener); } allListeners.add(listener); } } ``` 我们看到最后是通过supportsEvent方法进行判断的: ```java 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)); } ``` 到目前分为2种情况: 1. listener是GenericApplicationListener子类时,通过supportsEventType与supportsSourceType返回值进行判断是否支持当前事件。 2. 其他情况创建GenericApplicationListenerAdapter对象,进行转换后判断。 所以我们还需要再看一下GenericApplicationListenerAdapter类,首先看一下构造方法 ```java public GenericApplicationListenerAdapter(ApplicationListener<?> delegate) { Assert.notNull(delegate, "Delegate listener must not be null"); this.delegate = (ApplicationListener<ApplicationEvent>) delegate; this.declaredEventType = resolveDeclaredEventType(this.delegate); } ``` 主要看一下resolveDeclaredEventType方法 ```java @Nullable private static ResolvableType resolveDeclaredEventType(ApplicationListener<ApplicationEvent> listener) { ResolvableType declaredEventType = resolveDeclaredEventType(listener.getClass()); if (declaredEventType == null || declaredEventType.isAssignableFrom(ApplicationEvent.class)) { Class<?> targetClass = AopUtils.getTargetClass(listener); if (targetClass != listener.getClass()) { declaredEventType = resolveDeclaredEventType(targetClass); } } return declaredEventType; } @Nullable static ResolvableType resolveDeclaredEventType(Class<?> listenerType) { ResolvableType eventType = eventTypeCache.get(listenerType); if (eventType == null) { eventType = ResolvableType.forClass(listenerType).as(ApplicationListener.class).getGeneric(); eventTypeCache.put(listenerType, eventType); } return (eventType != ResolvableType.NONE ? eventType : null); } ``` 通过代码我们看到成员变量declaredEventType就是这个监听器上面范型类型。 下面我们看一下主要的两个方法: ```java @Override @SuppressWarnings("unchecked") public boolean supportsEventType(ResolvableType eventType) { if (this.delegate instanceof SmartApplicationListener) { Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.resolve(); return (eventClass != null && ((SmartApplicationListener) this.delegate).supportsEventType(eventClass)); } else { return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType)); } } @Override public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) { return supportsEventType(ResolvableType.forClass(eventType)); } @Override public boolean supportsSourceType(@Nullable Class<?> sourceType) { return !(this.delegate instanceof SmartApplicationListener) || ((SmartApplicationListener) this.delegate).supportsSourceType(sourceType); } ``` 一方面对于SmartApplicationListener的判断,与GenericApplicationListener处理逻辑相同 另一方面根据范型与发送的事件类型进行匹配,如果当前事件类型是范型的子类,说明当前监听器支持当前事件,可以发送。 ## 总结 当前类主要作用就是判断出所有的监听器中,哪些符合当前事件。对于符合要求的触发事件。具体判断逻辑如下: 1. 监听器是GenericApplicationListener与SmartApplicationListener的子类,则通过方法判断 2. 其他情况根据监听器的范型判断,如果发送事件的类型是范型的子类。则发送当前事件 # ApplicationListener 前面分析中,我们知道对于不同事件,最终都会发送给响应的ApplicationListener监听器中。在springboot默认情况下有过个监听器。 目前我们先分析最主要的一个 EnvironmentPostProcessorApplicationListener
回帖
消灭零回复
提交回复
热议榜
java 相关知识分享
8
好的程序员与不好的程序员
6
写给工程师的十条精进原则
5
spring boot以jar包运行配置的logback日志文件没生成
5
一步一步分析SpringBoot启动源码(一)
5
MockMvc测试
5
【吐槽向】是不是有个吐槽的板块比较好玩
4
logstash jdbc同步mysql多表数据到elasticsearch
3
IntelliJ IDEA 优质License Server
3
.gitignore忽略规则
3
SpringBoot启动源码分析
3
一步一步分析SpringBoot启动源码(三)
3
2
一步一步分析SpringBoot启动源码(二)
2
积分不够将无法发表新帖
2
官方产品
Meta-Boot - 基于MCN
MCN - 快速构建SpringBoot应用
微信扫码关注公众号