本文是承接上一篇寫的:springboot源碼分析(四)-監聽器實現原理(上)
概述
上一篇文章已經把監聽器設計模式介紹一下,不太懂的可以先看一下上一篇文章,有助於理解本文,那本文就從源碼角度分析springboot中監聽器實現原理。
spring中的監聽器都是實現了如下兩個接口中的其中的一個
@FunctionalInterface public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { void onApplicationEvent(E var1); }
public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered { boolean supportsEventType(Class<? extends ApplicationEvent> var1); default boolean supportsSourceType(@Nullable Class<?> sourceType) { return true; } default int getOrder() { return 2147483647; } }
說一下這兩個接口的區別:第一個接口是所有的監聽器都要實現的,里面就一個抽象方法,是一個函數式接口,第二個接口相比於第一個接口,擴展了幾個方法,其中
supportsEventType(Class<? extends ApplicationEvent> var1)
方法跟這個監聽器支持什么事件有關系,一會源碼的時候就知道這個方法的作用了
首先看一下系統監聽器初始化過程,和系統初始化器一樣都是放在一個列表中。
SpringApplication初始化函數如下:
private List<ApplicationListener<?>> listeners;
public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
this.listeners = new ArrayList(listeners);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.sources = new LinkedHashSet(); this.bannerMode = Mode.CONSOLE; this.logStartupInfo = true; this.addCommandLineProperties = true; this.addConversionService = true; this.headless = true; this.registerShutdownHook = true; this.additionalProfiles = new HashSet(); this.isCustomEnvironment = false; this.lazyInitialization = false; this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet(Arrays.asList(primarySources)); this.webApplicationType = WebApplicationType.deduceFromClasspath(); this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); //這一行就是初始化監聽器的 this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = this.deduceMainApplicationClass(); }
進入this.getSpringFactoriesInstances(ApplicationListener.class)方法
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) { return this.getSpringFactoriesInstances(type, new Class[0]); } private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = this.getClassLoader(); //從META-INF/spring-factories中加載監聽器 Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); //實例化監聽器 List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); //排序監聽器 AnnotationAwareOrderComparator.sort(instances); return instances; }
看過我前幾篇系統初始化器的朋友應該對這幾個方法都不陌生,因為系統初始化器也是調用的這個方法,當時詳細了解析了這幾個方法的源碼,在這里就不重復了,感興趣的朋友可以翻翻我的前幾篇文章,都是springboot源碼系列的。
看過上篇文章的朋友都知道,監聽器模式需要幾個條件。
- 目標
- 具體目標
- 監聽器
- 事件(其實事件就是目標中發生了什么事,不同事對應不同的事件)
- 觸發場景(這個上一篇文章中Test中,其實目標中執行了什么東西,然后觀察者才可以觀察到變化,這個其實就是觸發場景)
下面就從上面的幾個角度來分析
抽象目標
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware { //存放監聽器的地方 private final AbstractApplicationEventMulticaster.ListenerRetriever defaultRetriever = new AbstractApplicationEventMulticaster.ListenerRetriever(false); //新增監聽器 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 void removeApplicationListener(ApplicationListener<?> listener) { synchronized(this.retrievalMutex) { this.defaultRetriever.applicationListeners.remove(listener); this.retrieverCache.clear(); } } //省略N個其他方法 }
可以發現其實這個和我們上一節講的那個差不多,就是有幾個存放監聽器的列表,並且實現新增或者刪除監聽器的方法,但是這里沒有廣播后者叫着通知的方法,就是通知監聽器執行的方法,這個方法在具體的目標中實現。
具體目標
//這里可以發現繼承了抽象目標
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
//這個方法就是廣播事件的 public void multicastEvent(ApplicationEvent event) { this.multicastEvent(event, this.resolveDefaultEventType(event)); } public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event); Executor executor = this.getTaskExecutor(); Iterator var5 = this.getApplicationListeners(event, type).iterator(); while(var5.hasNext()) { ApplicationListener<?> listener = (ApplicationListener)var5.next(); if (executor != null) { executor.execute(() -> { this.invokeListener(listener, event); }); } else { this.invokeListener(listener, event); } } }
//省略N個方法。。。
}
監聽器
下面來看一下springboot中都有哪些監聽器
這些個監聽器先不要管,一會我會分析幾個具體監聽器。
事件
這些事件在SpringApplication初始化過程中基本都會用到,我會分析其中的一兩個事件
觸發場景
看一下SpringApplication.run()方法
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList(); this.configureHeadlessProperty();
//這里就是springboot比較講究的地方,一會分析這個 SpringApplicationRunListeners listeners = this.getRunListeners(args);
//這里就是觸發場景 listeners.starting(); Collection exceptionReporters; //省略N行不相關的 }
進入this.getRunListeners(args);
private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
//這里新建對象,我們看一下這個對象,里面的參數this.getSpringFactoriesInstances這個就是從META-INF/spring-factories中獲取監聽器的,返回一個實例化好列表,但是這里注意
//這里后去的監聽器是SpringApplicationListener,和上面初始化監聽器列表獲取的是不一樣的 return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)); }
進入new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
class SpringApplicationRunListeners { private final Log log; private final List<SpringApplicationRunListener> listeners; SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) { this.log = log; this.listeners = new ArrayList(listeners); } //SpringApplication開始啟動事件 void starting() { Iterator var1 = this.listeners.iterator(); while(var1.hasNext()) { SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next(); listener.starting(); } } //SpringApplication環境准備就緒事件 void environmentPrepared(ConfigurableEnvironment environment) { Iterator var2 = this.listeners.iterator(); while(var2.hasNext()) { SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next(); listener.environmentPrepared(environment); } } //SpringApplication上下文准備事件 void contextPrepared(ConfigurableApplicationContext context) { Iterator var2 = this.listeners.iterator(); while(var2.hasNext()) { SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next(); listener.contextPrepared(context); } } }
這個類的作用是什么呢?他的類名后面也帶有Listener,但是他並不是一個監聽器,而是一個封裝了目標中會產生的各個事件的封裝類,在上一篇文章中,我們是直接在具體目標中實例化事件,這里他沒有在具體目標中直接實例化目標,而是讓事件的實例化和具體目標分開,這樣可以讓系統的耦合性降低。
這個類中有一個列表:List<SpringApplicationRunListener> listeners;我們看一下這個SpringApplicationRunListener
public interface SpringApplicationRunListener { default void starting() { } default void environmentPrepared(ConfigurableEnvironment environment) { } default void contextPrepared(ConfigurableApplicationContext context) { } default void contextLoaded(ConfigurableApplicationContext context) { } default void started(ConfigurableApplicationContext context) { } default void running(ConfigurableApplicationContext context) { } default void failed(ConfigurableApplicationContext context, Throwable exception) { } }
這個接口就是定義了各種要執行的事件,然后我們看一下這個接口的實現類,就只有一個實現類
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered { private final SpringApplication application; private final String[] args;
//這個里面有一個廣播器屬性,其實就是我們說的具體目標 private final SimpleApplicationEventMulticaster initialMulticaster; public EventPublishingRunListener(SpringApplication application, String[] args) { this.application = application; this.args = args; this.initialMulticaster = new SimpleApplicationEventMulticaster(); Iterator var3 = application.getListeners().iterator(); while(var3.hasNext()) { ApplicationListener<?> listener = (ApplicationListener)var3.next(); this.initialMulticaster.addApplicationListener(listener); } } public int getOrder() { return 0; } public void starting() { this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args)); } public void environmentPrepared(ConfigurableEnvironment environment) { this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment)); } public void contextPrepared(ConfigurableApplicationContext context) { this.initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context)); }
//省略N個方法。。。 }
springboot就是使用這個玩意來連接觸發場景和調用具體的監聽器去執行的
OK,我們接下來來分析SimpleApplicationEventMulticaster的multicastEvent()方法
public void multicastEvent(ApplicationEvent event) { this.multicastEvent(event, this.resolveDefaultEventType(event)); } public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event); Executor executor = this.getTaskExecutor();
//<1.1>獲取對這個事件感興趣的監聽器 Iterator var5 = this.getApplicationListeners(event, type).iterator(); while(var5.hasNext()) { ApplicationListener<?> listener = (ApplicationListener)var5.next(); if (executor != null) { executor.execute(() -> { this.invokeListener(listener, event); }); } else {
//<1.2>具體讓監聽器執行事件的方法 this.invokeListener(listener, event); } } }
我們進入<1.1>,this.getApplicationListeners(event, type).iterator();
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) { Object source = event.getSource(); Class<?> sourceType = source != null ? source.getClass() : null; AbstractApplicationEventMulticaster.ListenerCacheKey cacheKey = new AbstractApplicationEventMulticaster.ListenerCacheKey(eventType, sourceType);
//先從緩存中獲取,由於我們初次啟動,緩存中是不存在的 AbstractApplicationEventMulticaster.ListenerRetriever retriever = (AbstractApplicationEventMulticaster.ListenerRetriever)this.retrieverCache.get(cacheKey); if (retriever != null) { return retriever.getApplicationListeners(); } else if (this.beanClassLoader == null || ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader))) { //添加同步鎖 synchronized(this.retrievalMutex) {
//再次從緩存中獲取,防止在執行這個操作的過程中,別的線程向里面寫了數據 retriever = (AbstractApplicationEventMulticaster.ListenerRetriever)this.retrieverCache.get(cacheKey); if (retriever != null) { return retriever.getApplicationListeners(); } else { retriever = new AbstractApplicationEventMulticaster.ListenerRetriever(true);
//這一步就是獲取對這個事件感興趣的監聽器的關鍵步驟 Collection<ApplicationListener<?>> listeners = this.retrieveApplicationListeners(eventType, sourceType, retriever); this.retrieverCache.put(cacheKey, retriever); return listeners; } } } else { return this.retrieveApplicationListeners(eventType, sourceType, (AbstractApplicationEventMulticaster.ListenerRetriever)null); } }
我們進入this.retrieveApplicationListeners(eventType, sourceType, retriever);
private Collection<ApplicationListener<?>> retrieveApplicationListeners(ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable AbstractApplicationEventMulticaster.ListenerRetriever retriever) {
//新建list,用來存放對該事件感興趣的監聽器 List<ApplicationListener<?>> allListeners = new ArrayList(); LinkedHashSet listeners; LinkedHashSet listenerBeans; synchronized(this.retrievalMutex) {
//這里this.defaultRetriever.applicationListeners就是在SpringApplication初始化的時候從META-INF/spring-factories中獲取的監聽器 listeners = new LinkedHashSet(this.defaultRetriever.applicationListeners); listenerBeans = new LinkedHashSet(this.defaultRetriever.applicationListenerBeans); } Iterator var7 = listeners.iterator(); //把系統中所有的監聽器都遍歷一遍,找到對這個事件感興趣的監聽器 while(var7.hasNext()) { ApplicationListener<?> listener = (ApplicationListener)var7.next();
//這里就是判斷是否感興趣的核心方法,我們進入看看 if (this.supportsEvent(listener, eventType, sourceType)) { if (retriever != null) { retriever.applicationListeners.add(listener); } allListeners.add(listener); } } //第一次初始化,listenerBeans是空的,這里就不分析了 if (!listenerBeans.isEmpty()) { ConfigurableBeanFactory beanFactory = this.getBeanFactory(); Iterator var15 = listenerBeans.iterator(); while(var15.hasNext()) { String listenerBeanName = (String)var15.next(); try { if (this.supportsEvent(beanFactory, listenerBeanName, eventType)) { ApplicationListener<?> listener = (ApplicationListener)beanFactory.getBean(listenerBeanName, ApplicationListener.class); if (!allListeners.contains(listener) && this.supportsEvent(listener, eventType, sourceType)) { if (retriever != null) { 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 var11) { } } }
進入this.supportsEvent(listener, eventType, sourceType)
protected boolean supportsEvent(ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
//先判斷監聽器是不是GenericApplicationListener GenericApplicationListener smartListener = listener instanceof GenericApplicationListener ? (GenericApplicationListener)listener : new GenericApplicationListenerAdapter(listener);
//這里是判斷是不是感興趣的 return ((GenericApplicationListener)smartListener).supportsEventType(eventType) && ((GenericApplicationListener)smartListener).supportsSourceType(sourceType); }
進入((GenericApplicationListener)smartListener).supportsEventType(eventType)
public boolean supportsEventType(ResolvableType eventType) {
//先判斷這個監聽器是不是SmartApplication類型的 if (this.delegate instanceof SmartApplicationListener) { Class<? extends ApplicationEvent> eventClass = eventType.resolve();
//<3.1> 如果是SmartApplicationListener類型的,可以直接使用delegate中的supportsEventType方法判斷,為什么可以這樣判斷呢?
//因為在SmartApplicationListener接口中有這個抽象方法,他的實現類都會實現這個方法
return eventClass != null && ((SmartApplicationListener)this.delegate).supportsEventType(eventClass); } else {
//這個declaredEventType在GenericApplicationListenerAdapter初始化的時候已經賦值了,大家可以看一下這個類的構造方法
//<3.2> declaredEventType.isAssignableFrom(eventType); 這個方法就是判斷當前監聽器是否對這個事件感興趣的,這個怎么判斷呢?后面會說
return this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType); } }
ok,<3.1>中,我們就找一個實現了SmartApplicationListener接口的監聽器,在我上面的截圖中的ConfigFileApplicationListener,這個監聽器實現了
public class ConfigFileApplicationListener implements EnvironmentPostProcessor, SmartApplicationListener, Ordered { //可以發現這個監聽器對兩個事件感興趣,只要是下面的兩個事件,他都會返回true public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) { return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType) || ApplicationPreparedEvent.class.isAssignableFrom(eventType); }
}
<3.2>處, this.declaredEventType.isAssignableFrom(eventType);這個方法有什么有呢?
我舉個例子大家就明白了。
在上面截圖的監聽器中有一個CloudFoundryVcapEnvironmentPostProcessor,我們看一下這個類的定義
public class CloudFoundryVcapEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered, ApplicationListener<ApplicationPreparedEvent> {}
這個類在實現ApplicationListener的時候指定了具體的事件,就是ApplicationPreparedEvent,那<3.2>處的代碼,假設當前正在遍歷的就是這個監聽器,那這個方法就是判斷當前的事件是不是ApplicationPreparedEvent,如果是就返回true
也許分析到這里大家已經找不着北了,spring的代碼寫的就是這種,一層套一層,,,,,,,,,,,不過我們的分析還沒有完成,我們在上面已經找到了對ApplicationStartingEvent事件感興趣的監聽器,如下:
我們找到了4個對這個事件感興趣的監聽器,那我們要執行對應的回調方法,我們拿其中的一個監聽器舉例,就拿第一個LoggingApplicationListener,我們看一下這個監聽器會做什么吧,😄
public void onApplicationEvent(ApplicationEvent event) { if (event instanceof ApplicationStartingEvent) { this.onApplicationStartingEvent((ApplicationStartingEvent)event); } else if (event instanceof ApplicationEnvironmentPreparedEvent) { this.onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)event); } else if (event instanceof ApplicationPreparedEvent) { this.onApplicationPreparedEvent((ApplicationPreparedEvent)event); } else if (event instanceof ContextClosedEvent && ((ContextClosedEvent)event).getApplicationContext().getParent() == null) { this.onContextClosedEvent(); } else if (event instanceof ApplicationFailedEvent) { this.onApplicationFailedEvent(); } }
可以發現這個監聽器可以處理很多的事件,基本上就是打印日志。
以上,基本上把監聽器的原理給介紹完了,總結一下,從觸發場景產生事件開始,到尋找對這個事件感興趣的監聽器,在最后執行回調,就是整個監聽器的執行鏈路,在判斷監聽器是否對事件感興趣的時候,把監聽器分為兩種,一種是實現了SmartApplicationListener的,另一個種是實現了ApplicationListener的,前者會調用監聽器內部的supportEventType()方法來判斷當前監聽器是否對該事件感興趣,后者則是直接調用declaredEventType.isAssignableFrom(eventType);來判斷當前監聽器是否對該事件感興趣。下一篇文章我會自定義幾個監聽器,加入到springboot的啟動監聽器列表中,看一下執行的結果。
番外話:如果大家覺得這文章寫的又臭又長,很凌亂,那抱歉了,因為這個系列的文章就是我學習springboot過程中整理的一種類似筆記的東西,由於本身水平確實有限,各位看官老爺就多擔待。