注:SpringBoot版本2.5.2
一、監(jiān)聽器的加載
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//這里就用了SPI技術(shù)加載spring-factories定義的ApplicationListener實現(xiàn)類
//然后把這些監(jiān)聽器保存到SpringApplication對象中
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
這里以springboot的META-INFO下的spring-factories為例
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.env.EnvironmentPostProcessorApplicationListener
可以看到這里加載了10個定義在所有jar中的spring-factories文件中定義的ApplicationListener實現(xiàn)類。
二、廣播器方法的調(diào)度類SpringApplicationRunListener的加載和初始化
//SpringApplication
public ConfigurableApplicationContext run(String... args) {
//.....
//這里看到有加載SpringApplicationRunListeners對象的方法
//該對象持有 SpringApplicationRunListener 對象的數(shù)組 ,從名字可知這個對象是驅(qū)動listner做一下操作的紫岩,主要定義了廣播事件的方法
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
//.....
}
//SpringApplication
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
this.applicationStartup);
}
我們看到有一個new SpringApplicationRunListeners的語句,里面有一個參數(shù)使用了getSpringFactoriesInstances方法獲取的,熟悉SpringBoot的朋友們應(yīng)該知道這里又是使用SPI的方式去spring-factories下面找到給定的接口類的實現(xiàn)類慰毅,然后把他們加載進來,這里給的指定接口類是SpringApplicationRunListener扎阶。
//new SpringApplicationRunListeners進入到該類的構(gòu)造器方法
class SpringApplicationRunListeners {
//記錄日志的對象
private final Log log;
//SpringApplicationRunListener對象的存儲列表
private final List<SpringApplicationRunListener> listeners;
//啟動類對象
private final ApplicationStartup applicationStartup;
//SpringApplicationRunListeners 的構(gòu)造方法
SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners,
ApplicationStartup applicationStartup) {
this.log = log;
this.listeners = new ArrayList<>(listeners);
this.applicationStartup = applicationStartup;
}
}
知道了SpringApplicationRunListener的實現(xiàn)類是采用了SPI的方式加載的汹胃,那我們就去參考SpringBoot的spring-factories文件,看一下文件中定義的SpringApplicationRunListener實現(xiàn)類有哪些
# RunListeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
可以看到這里只定義了一個EventPublishingRunListener
三东臀、廣播器的加載
上面指出了廣播器調(diào)度類的加載着饥,從設(shè)計模式的角度,一個調(diào)度類應(yīng)該是以屬性組合的關(guān)系持有這他調(diào)度的對象惰赋,這里的廣播器調(diào)度類也持有一個廣播器對象宰掉,我們看之前加載的廣播器調(diào)度類的結(jié)構(gòu),可以看到持有這一個SimpleApplicationEventMulticaster廣播器對象赁濒。并且在使用SPI加載的時候就默認(rèn)調(diào)用了唯一的構(gòu)造方法初始化了這個廣播器對象轨奄,以及這個廣播器的監(jiān)聽器列表。
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
//SpringApplication對象成員變量
private final SpringApplication application;
//啟動參數(shù)數(shù)組
private final String[] args;
//事件的廣播器
private final SimpleApplicationEventMulticaster initialMulticaster;
//構(gòu)造器
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
//把SpringApplication對象的構(gòu)造階段(SPI)加載的監(jiān)聽器列表listeners存儲到廣播器的監(jiān)聽器列表中
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
}
從該類的定義可知
①這個對象持有SpringApplication對象拒炎,可以從這個對象中或的創(chuàng)建SpringApplication對象的時候加載的listener列表挪拟。
②持有廣播器SimpleApplicationEventMulticaster對象
③只定義了一個構(gòu)造方法,說明當(dāng)使用SPI加載該類的時候默認(rèn)調(diào)用的就是以上的方法击你,則這些參數(shù)就在加載進來的時候就已經(jīng)初始化玉组,例如監(jiān)聽器列表。
3.1廣播器的監(jiān)聽器存儲位置
看一下這些監(jiān)聽器被添加到了廣播器的哪里
this.initialMulticaster.addApplicationListener(listener);
//AbstractApplicationEventMulticaster
public abstract class AbstractApplicationEventMulticaster
implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
//持有的默認(rèn)檢索器丁侄,存儲在new SpringApplication對象的時候使用SPI加載進來的監(jiān)聽器對象Listener列表
private final DefaultListenerRetriever defaultRetriever = new DefaultListenerRetriever();
//內(nèi)部類
private class DefaultListenerRetriever {
//存儲ApplicationListener對象集合的set
public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
//存儲聲明的ApplicationListener的bean的名稱集合的set
public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
}
//在之前提到的this.initialMulticaster.addApplicationListener(listener);步驟調(diào)用的
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.defaultRetriever) {
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
可以看到這些監(jiān)聽器都被添加進了廣播器的 defaultRetriever 對象屬性中惯雳。
到這里我們就知道SpringApplicationRunListeners對象已經(jīng)加載完了,而且明確了以下關(guān)系鸿摇;
SpringApplicationRunListeners對象-》持有EventPublishingRunListener數(shù)組-》 每一個EventPublishingRunListener都持有一個SimpleApplicationEventMulticaster廣播器對象-》這個廣播器持有DefaultListenerRetriever檢索器對象-》 這個檢索器對象持有SpringApplication創(chuàng)建的時候加載的監(jiān)聽器列表石景。
后續(xù)的發(fā)布事件操作將通過SpringApplicationRunListeners對象封裝的方法然后for循環(huán)調(diào)用每EventPublishingRunListener的對象持有的廣播器SimpleApplicationEventMulticaster對象進行事件發(fā)布。
四户辱、事件發(fā)布流程
從SpringApplication的run方法可以看到第一個應(yīng)用程序事件的發(fā)布 - 》 使用廣播器調(diào)度對象數(shù)組對象發(fā)布事件ApplicationStartingEvent
4.1 廣播器調(diào)度對象數(shù)組對象調(diào)用對應(yīng)的方法
//SpringApplication
public ConfigurableApplicationContext run(String... args) {
......
listeners.starting(bootstrapContext, this.mainApplicationClass);
......
}
4.2 廣播器調(diào)度對象數(shù)組對象循環(huán)調(diào)用數(shù)組里面的廣播器調(diào)度對象鸵钝,每個對象再調(diào)用事件對應(yīng)的方法
//SpringApplicationRunListeners
void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
// ...........
}
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
Consumer<StartupStep> stepAction) {
// ...........
this.listeners.forEach(listenerAction);
// ...........
}
4.3 廣播器調(diào)度器再調(diào)用自己持有的廣播器對象調(diào)用廣播方法發(fā)布事件
從上方的傳入?yún)?shù) Consumer<StartupStep> stepAction 可知,這里是分別調(diào)用了List<SpringApplicationRunListener> listeners數(shù)組中所有的SpringApplicationRunListener對象的starting方法
//EventPublishingRunListener
public void starting(ConfigurableBootstrapContext bootstrapContext) {
//從第二點我們就知道每一個runListener對象都持有廣播器SimpleApplicationEventMulticaster對象,
//同時這個eventMulticaste對象還持有DefaultListenerRetriever類對象應(yīng)用,而EventPublishingRunListener對象在創(chuàng)建的時候
//就把DefaultListenerRetriever對象的listener數(shù)組初始化為SPI加載的所有l(wèi)istener集合
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
}
先看ApplicationStartingEvent事件對象的創(chuàng)建方法(構(gòu)造器方法)
//ApplicationStartingEvent
public ApplicationStartingEvent(ConfigurableBootstrapContext bootstrapContext, SpringApplication application,
String[] args) {
super(application, args);
this.bootstrapContext = bootstrapContext;
}
從構(gòu)造方法可以看的出來,主要初始化三個數(shù)據(jù)
①設(shè)置加載上下文
②設(shè)置事件的來源,是從哪個對象創(chuàng)建的事件
③設(shè)置參數(shù)
五、監(jiān)聽器的篩選
再看廣播器SimpleApplicationEventMulticaster對象的multicastEvent方法
//SimpleApplicationEventMulticaster
public void multicastEvent(ApplicationEvent event) {
//event就是事件對象,resolveDefaultEventType(event)返回的是對event進行包裝
multicastEvent(event, resolveDefaultEventType(event));
}
可以看到這個type是記錄了這個事件的類型,加載器,父類以及這個類的繼承結(jié)構(gòu)樹等信息
5.1 廣播器的廣播方法
//SimpleApplicationEventMulticaster
//該方法主要用于根據(jù)事件的類型,獲取到對這個事件感興趣的監(jiān)聽器,然后調(diào)用監(jiān)聽器的監(jiān)聽方法onApplication執(zhí)行對應(yīng)的事件響應(yīng)邏輯
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
//getApplicationListeners 獲取對這個事件感興趣的監(jiān)聽器
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
//調(diào)用這些監(jiān)聽器的onApplication方法對這個事件做出響應(yīng)
invokeListener(listener, event);
}
}
}
5.2 根據(jù)事件類型篩選監(jiān)聽器的(getApplicationListeners)
5.2.1 根據(jù)事件類型加來源獲取存儲監(jiān)聽該事件的監(jiān)聽器的容器
可以看到下方方法中是使用了一個ConcurrentHashMap來存儲事件和監(jiān)聽器的關(guān)系的庐镐,避免每次都需要根據(jù)事件類型查詢對應(yīng)的監(jiān)聽器恩商,當(dāng)已經(jīng)在緩存中存在的關(guān)系,則直接根據(jù)事件來構(gòu)造key值必逆,從緩存中直接獲取監(jiān)聽器列表怠堪;否則就構(gòu)造一個存儲對應(yīng)的監(jiān)聽器容器對象存放到緩存中揽乱。
//AbstractApplicationEventMulticaster
/**
* Return a Collection of ApplicationListeners matching the given event type.
*/
private final DefaultListenerRetriever defaultRetriever = new DefaultListenerRetriever();
final Map<ListenerCacheKey, CachedListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);
protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
//首先先獲取事件的源 source,也就是 SpringApplication
Object source = event.getSource();
//獲得source的class type
Class<?> sourceType = (source != null ? source.getClass() : null);
//通過sourceType和eventType構(gòu)造一個緩存key
//目的是若當(dāng)前已經(jīng)獲得過對當(dāng)前事件感興趣的監(jiān)聽器列表粟矿,則從緩存中讀取凰棉,
//不必再重新進行計算哪些監(jiān)聽器對該事件感興趣,提升了效率
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);
//第一次調(diào)用的話retriever為null
if (existingRetriever == null) {
// Caching a new ListenerRetriever if possible
//如果需要緩存一個新的ListenerRetriever(監(jiān)聽器檢索器)
//這里以前是用鎖鎖住了陌粹,獲取listener列表和放入cache是在同步塊撒犀,但是這樣效率太低了。使用鎖應(yīng)該盡可能的使得鎖的粒度更低
//所以相比于以前掏秩,這里進行了優(yōu)化或舞,不用鎖而是使用了普通的putIfAbsent方法,先做簡單的過濾掉大部分不爭用鎖的情況
//再在需要使用鎖的時候在retrieveApplicationListeners進行小粒度的鎖
if (this.beanClassLoader == null || (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
newRetriever = new CachedListenerRetriever();
//如果緩存中已存在蒙幻,則會返回緩存中的對象映凳,否則返回空
//注意-》這里只是存儲了用于存儲listener列表的對象-》對于未存入緩存的listener列表在
//下一步retrieveApplicationListeners處理
existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
if (existingRetriever != null) {
//緩存中已經(jīng)有了數(shù)據(jù)就不需要填充進去了,當(dāng)cache中無數(shù)據(jù)的時候
//putIfAbsent會返回null邮破,有數(shù)據(jù)則會返回舊數(shù)據(jù)而不執(zhí)行put的操作
newRetriever = null;
}
}
}
//緩存中retriever不為null诈豌,直接返回retriever的獲取監(jiān)聽器方法
if (existingRetriever != null) {
Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();
if (result != null) {
return result;
}
/**
這里會出現(xiàn)緩存中存在檢索器,但是監(jiān)聽器為空的情況是因為當(dāng)另一個線程
設(shè)置existingRetriever的時候被感知到了
另一個線程比當(dāng)前線程調(diào)用putIfAbsent方法快一點抒和,參考CurrentHashMap的特點矫渔,
所以這個線程可以感知到緩存中已經(jīng)存在existingRetriever了,
但是另一個線程也是執(zhí)行到這里构诚,所以并不執(zhí)行接下來的etrieveApplicationListeners初始化
檢索器持有的監(jiān)聽器蚌斩,而是稍后繼續(xù)執(zhí)行,所以導(dǎo)致這里獲取到的監(jiān)聽器還是空的铆惑,
所以這里的處理是當(dāng)前線程默認(rèn)已經(jīng)把監(jiān)聽器加載進去了范嘱,
在下一步方法中通過newRetriever為空 來判斷
是否對檢索器進行監(jiān)聽器列表的屬性的賦值,默認(rèn)是把已經(jīng)加載到SpringApplication對象
持有的監(jiān)聽器列表返回(因為另一個線程如果填充也是填充這些)
**/
//ConcurrentHashMap的參考鏈接:https://www.cnblogs.com/xiaoxi/p/7474026.html
// 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.
}
//No ListenerRetriever caching -> no synchronization necessary
return retrieveApplicationListeners(eventType, sourceType, newRetriever);
}
5.3 監(jiān)聽器容器對象的初始化
當(dāng)上面的方法設(shè)置好存儲監(jiān)聽器的容器后员魏,就到了初始化這個檢索器設(shè)置事件和對該事件感興趣的監(jiān)聽器列表的方法了-》retrieveApplicationListeners方法丑蛤。
這個階段主要的問題就是根據(jù)廣播的事件的類型篩選出哪些監(jiān)聽器需要做出響應(yīng),然后把這些監(jiān)聽器以 事件類型加來源:對這個事件感興趣的監(jiān)聽器列表 的形式存儲在 concurrentHashMap 中撕阎。
//AbstractApplicationEventMulticaster
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) {
//這里defaultRetriever的監(jiān)聽器列表是在SpringApplication創(chuàng)建的時候初始化和賦值
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) {
//遍歷這些監(jiān)聽器受裹,看看那些監(jiān)聽器是歸這個事件感興趣的
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;
}
5.3.1 supportsEvent 判斷是否支持監(jiān)聽這個事件
觀察supportsEvent的內(nèi)部邏輯看看是如何判斷哪些監(jiān)聽器對這個事件感興趣
//AbstractApplicationEventMulticaster
protected boolean supportsEvent(
ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
//由于supportsEventType方法只支持GenericApplicationListener類型的監(jiān)聽器,所以先使用設(shè)配器
//抽取出監(jiān)聽器的聲明的指定監(jiān)聽的問題的類型以及監(jiān)聽器的對象虏束,創(chuàng)建一個普通的監(jiān)聽器
//對象 GenericApplicationListener棉饶,便于后續(xù)對這些不同的監(jiān)聽器采取一樣的判斷操作
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
在調(diào)用適配器轉(zhuǎn)換為GenericApplicationListenerAdapter(繼承了GenericApplicationListener)對象后,通過這個對象調(diào)用supportsEventType方法和supportsSourceType方法
//GenericApplicationListenerAdapter
public GenericApplicationListenerAdapter(ApplicationListener<?> delegate) {
Assert.notNull(delegate, "Delegate listener must not be null");
//委托適配的監(jiān)聽器對象
this.delegate = (ApplicationListener<ApplicationEvent>) delegate;
//解析該監(jiān)聽器感興趣的事件類型
//declaredEventType 這個監(jiān)聽器的泛型指定的類型(聲明的類型是)
this.declaredEventType = resolveDeclaredEventType(this.delegate);
}
//解析該監(jiān)聽器感興趣的事件類型
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;
}
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);
}
調(diào)用設(shè)配器轉(zhuǎn)換完后可以知道這個監(jiān)聽器的監(jiān)聽事件類型镇匀,以及監(jiān)聽器對象
接下來就是根據(jù)適配后的對象調(diào)用方法supportsEventType和supportsSourceType判斷這個監(jiān)聽器對該事件感興趣與否照藻。
public boolean supportsEventType(ResolvableType eventType) {
//根據(jù)這個方法的調(diào)用方判斷這個對象的類別(通過之前的Adapter適配后設(shè)置或者原本就有的delegate來判斷)
if (this.delegate instanceof GenericApplicationListener) {
//為真則調(diào)用這個對象的supportsEventType
return ((GenericApplicationListener) this.delegate).supportsEventType(eventType);
}
else if (this.delegate instanceof SmartApplicationListener) {
Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.resolve();
return (eventClass != null && ((SmartApplicationListener) this.delegate).supportsEventType(eventClass));
}
else {
//不為真則根據(jù)這個監(jiān)聽器監(jiān)聽的事件類型declaredEventType和傳進來的時間類型eventType相匹配,返回這個判斷結(jié)果
//declaredEventType為空則說明這個監(jiān)聽器沒有設(shè)置監(jiān)聽的事件類型汗侵,則監(jiān)聽所有的事件幸缕,返回true
//不為空則對比聲明的監(jiān)聽類型是否和傳遞進來的事件類型是否一致
return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
}
}
這里有一個疑問為啥要單獨分開supportsEventType判斷群发,最后分支的else不適配特定類型的監(jiān)聽器?
當(dāng)smartListener.supportsEventType(eventType)為真的時候則進行事件來源的判斷
//GenericApplicationListenerAdapter
public boolean supportsSourceType(@Nullable Class<?> sourceType) {
//假如這個不是SmartApplicationListener的子類(GenericApplicationListener是SmartApplicationListener的子類)則為true发乔,
//而如果是屬于SmartApplicationListener的子類則再調(diào)用SmartApplicationListener對象的supportsSourceType方法
return !(this.delegate instanceof SmartApplicationListener) ||
((SmartApplicationListener) this.delegate).supportsSourceType(sourceType);
}
當(dāng)檢測出這個監(jiān)聽器對這個事件有監(jiān)聽的話就添加進監(jiān)聽器列表
//AbstractApplicationEventMulticaster
for (ApplicationListener<?> listener : listeners) {
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
filteredListeners.add(listener);
}
allListeners.add(listener);
}
}
最后按照事件類型加來源 - 》 監(jiān)聽器列表放到concurrentHashMap中緩存起來
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;
六熟妓、監(jiān)聽器對事件做出響應(yīng)
我們回到廣播器的廣播方法
//SimpleApplicationEventMulticaster
//該方法主要用于根據(jù)事件的類型,獲取到對這個事件感興趣的監(jiān)聽器,然后調(diào)用監(jiān)聽器的監(jiān)聽方法onApplication執(zhí)行對應(yīng)的事件響應(yīng)邏輯
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
//getApplicationListeners 獲取對這個事件感興趣的監(jiān)聽器
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
//調(diào)用這些監(jiān)聽器的onApplication方法對這個事件做出響應(yīng)
invokeListener(listener, event);
}
}
}
我們通過以上的方法已經(jīng)找到了對這個事件感興趣的監(jiān)聽器列表,之后就是遍歷這些監(jiān)聽器栏尚,然后分別調(diào)用這些監(jiān)聽器的對應(yīng)的響應(yīng)的方法onApplication
我們看invokerListener方法
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
//調(diào)用這些監(jiān)聽器的onApplication方法對這個事件做出響應(yīng)
invokeListener(listener, event);
}
這個方法傳入了需要調(diào)用的監(jiān)聽器起愈,以及事件對象
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 {
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass()) ||
(event instanceof PayloadApplicationEvent &&
matchesClassCastMessage(msg, ((PayloadApplicationEvent) event).getPayload().getClass()))) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception.
Log loggerToUse = this.lazyLogger;
if (loggerToUse == null) {
loggerToUse = LogFactory.getLog(getClass());
this.lazyLogger = loggerToUse;
}
if (loggerToUse.isTraceEnabled()) {
loggerToUse.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
我們可以看到 listener.onApplicationEvent(event) 是主動調(diào)用了這個監(jiān)聽器的響應(yīng)方法的。
七译仗、總結(jié)
通過該監(jiān)聽器的加載流程中了解到SPI的加載這種方式的便利性告材,簡化了xml配置,為注解編程提供了切入點古劲;同時從廣播器調(diào)度器這種設(shè)計思想斥赋,通過封裝廣播方法從而簡化調(diào)用者發(fā)布事件,降低耦合度产艾,以及適配器的使用疤剑,SpringBoot中的事件發(fā)布機制。
八闷堡、參考鏈接
1隘膘、http://redmapleren.com/2020/01/17/%E8%B0%88%E8%B0%88SpringBoot%E7%9A%84%E7%9B%91%E5%90%AC%E5%99%A8/
2、
https://www.cnblogs.com/xiaoxi/p/7474026.html