写点什么

SpringBoot 启动加载监听器以及监听应用启动阶段事件

发布于: 10 小时前
SpringBoot启动加载监听器以及监听应用启动阶段事件

注:SpringBoot 版本 2.5.2


一、监听器的加载



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技术加载spring-factories定义的ApplicationListener实现类 //然后把这些监听器保存到SpringApplication对象中 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass();}
复制代码


这里以 springboot 的 META-INFO 下的 spring-factories 为例


# Application Listenersorg.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 实现类。


二、广播器方法的调度类

SpringApplicationRunListener 的加载和初始化


//SpringApplicationpublic ConfigurableApplicationContext run(String... args) {    //.....    //这里看到有加载SpringApplicationRunListeners对象的方法    //该对象持有 SpringApplicationRunListener 对象的数组 ,从名字可知这个对象是驱动listner做一下操作的,主要定义了广播事件的方法    SpringApplicationRunListeners listeners = getRunListeners(args);    listeners.starting(bootstrapContext, this.mainApplicationClass);     //.....}
复制代码


//SpringApplicationprivate 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 的语句,里面有一个参数使用了 getSpringFactoriesInstances 方法获取的,熟悉 SpringBoot 的朋友们应该知道这里又是使用 SPI 的方式去 spring-factories 下面找到给定的接口类的实现类,然后把他们加载进来,这里给的指定接口类是 SpringApplicationRunListener。


//new SpringApplicationRunListeners进入到该类的构造器方法class SpringApplicationRunListeners {            //记录日志的对象            private final Log log;            //SpringApplicationRunListener对象的存储列表            private final List<SpringApplicationRunListener> listeners;            //启动类对象            private final ApplicationStartup applicationStartup;            //SpringApplicationRunListeners 的构造方法            SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners,                    ApplicationStartup applicationStartup) {                this.log = log;                this.listeners = new ArrayList<>(listeners);                this.applicationStartup = applicationStartup;        }}
复制代码


知道了 SpringApplicationRunListener 的实现类是采用了 SPI 的方式加载的,那我们就去参考 SpringBoot 的 spring-factories 文件,看一下文件中定义的 SpringApplicationRunListener 实现类有哪些


# RunListenersorg.springframework.boot.SpringApplicationRunListener=\org.springframework.boot.context.event.EventPublishingRunListener
复制代码


可以看到这里只定义了一个 EventPublishingRunListener


三、广播器的加载

上面指出了广播器调度类的加载,从设计模式的角度,一个调度类应该是以属性组合的关系持有这他调度的对象,这里的广播器调度类也持有一个广播器对象,我们看之前加载的广播器调度类的结构,可以看到持有这一个 SimpleApplicationEventMulticaster 广播器对象。并且在使用 SPI 加载的时候就默认调用了唯一的构造方法初始化了这个广播器对象,以及这个广播器的监听器列表。


public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {     //SpringApplication对象成员变量     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();           //把SpringApplication对象的构造阶段(SPI)加载的监听器列表listeners存储到广播器的监听器列表中           for (ApplicationListener<?> listener : application.getListeners()) {                this.initialMulticaster.addApplicationListener(listener);           }     }}
复制代码


从该类的定义可知

①这个对象持有 SpringApplication 对象,可以从这个对象中或的创建 SpringApplication 对象的时候加载的 listener 列表。

②持有广播器 SimpleApplicationEventMulticaster 对象

③只定义了一个构造方法,说明当使用 SPI 加载该类的时候默认调用的就是以上的方法,则这些参数就在加载进来的时候就已经初始化,例如监听器列表。


3.1 广播器的监听器存储位置

看一下这些监听器被添加到了广播器的哪里


this.initialMulticaster.addApplicationListener(listener);
复制代码


//AbstractApplicationEventMulticasterpublic abstract class AbstractApplicationEventMulticaster    implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {      //持有的默认检索器,存储在new SpringApplication对象的时候使用SPI加载进来的监听器对象Listener列表      private final DefaultListenerRetriever defaultRetriever = new DefaultListenerRetriever();      //内部类      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);步骤调用的      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();      }}
复制代码


可以看到这些监听器都被添加进了广播器的 defaultRetriever 对象属性中。


到这里我们就知道 SpringApplicationRunListeners 对象已经加载完了,而且明确了以下关系;


SpringApplicationRunListeners 对象-》持有 EventPublishingRunListener 数组-》 每一个 EventPublishingRunListener 都持有一个 SimpleApplicationEventMulticaster 广播器对象-》这个广播器持有 DefaultListenerRetriever 检索器对象-》 这个检索器对象持有 SpringApplication 创建的时候加载的监听器列表。


后续的发布事件操作将通过 SpringApplicationRunListeners 对象封装的方法然后 for 循环调用每 EventPublishingRunListener 的对象持有的广播器 SimpleApplicationEventMulticaster 对象进行事件发布。


四、事件发布流程

从 SpringApplication 的 run 方法可以看到第一个应用程序事件的发布 - 》 使用广播器调度对象数组对象发布事件 ApplicationStartingEvent


4.1 广播器调度对象数组对象调用对应的方法


//SpringApplicationpublic ConfigurableApplicationContext run(String... args) {        ......        listeners.starting(bootstrapContext, this.mainApplicationClass);        ......}
复制代码


4.2 广播器调度对象数组对象循环调用数组里面的广播器调度对象,每个对象再调用事件对应的方法


//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 广播器调度器再调用自己持有的广播器对象调用广播方法发布事件

从上方的传入参数 Consumer<StartupStep> stepAction 可知,这里是分别调用了 List<SpringApplicationRunListener> listeners 数组中所有的 SpringApplicationRunListener 对象的 starting 方法


//EventPublishingRunListenerpublic void starting(ConfigurableBootstrapContext bootstrapContext) {    //从第二点我们就知道每一个runListener对象都持有广播器SimpleApplicationEventMulticaster对象,    //同时这个eventMulticaste对象还持有DefaultListenerRetriever类对象应用,而EventPublishingRunListener对象在创建的时候    //就把DefaultListenerRetriever对象的listener数组初始化为SPI加载的所有listener集合    this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));}
复制代码


先看 ApplicationStartingEvent 事件对象的创建方法(构造器方法)


//ApplicationStartingEvent
public ApplicationStartingEvent(ConfigurableBootstrapContext bootstrapContext, SpringApplication application,String[] args) { super(application, args); this.bootstrapContext = bootstrapContext;}
复制代码


从构造方法可以看的出来,主要初始化三个数据

①设置加载上下文

②设置事件的来源,是从哪个对象创建的事件

③设置参数

五、监听器的筛选

再看广播器 SimpleApplicationEventMulticaster 对象的 multicastEvent 方法


//SimpleApplicationEventMulticaster
public void multicastEvent(ApplicationEvent event) { //event就是事件对象,resolveDefaultEventType(event)返回的是对event进行包装 multicastEvent(event, resolveDefaultEventType(event));}
复制代码



可以看到这个 type 是记录了这个事件的类型,加载器,父类以及这个类的继承结构树等信息

5.1 广播器的广播方法


//SimpleApplicationEventMulticaster
//该方法主要用于根据事件的类型,获取到对这个事件感兴趣的监听器,然后调用监听器的监听方法onApplication执行对应的事件响应逻辑public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); Executor executor = getTaskExecutor(); //getApplicationListeners 获取对这个事件感兴趣的监听器 for (ApplicationListener<?> listener : getApplicationListeners(event, type)) { if (executor != null) { executor.execute(() -> invokeListener(listener, event)); } else { //调用这些监听器的onApplication方法对这个事件做出响应 invokeListener(listener, event); } }}
复制代码


5.2 根据事件类型筛选监听器

5.2.1 根据事件类型加来源获取存储监听该事件的监听器的容器

可以看到下方方法中是使用了一个 ConcurrentHashMap 来存储事件和监听器的关系的,避免每次都需要根据事件类型查询对应的监听器,当已经在缓存中存在的关系,则直接根据事件来构造 key 值,从缓存中直接获取监听器列表;否则就构造一个存储对应的监听器容器对象存放到缓存中。


//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构造一个缓存key //目的是若当前已经获得过对当前事件感兴趣的监听器列表,则从缓存中读取, //不必再重新进行计算哪些监听器对该事件感兴趣,提升了效率 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); //第一次调用的话retriever为null if (existingRetriever == null) { // Caching a new ListenerRetriever if possible //如果需要缓存一个新的ListenerRetriever(监听器检索器) //这里以前是用锁锁住了,获取listener列表和放入cache是在同步块,但是这样效率太低了。使用锁应该尽可能的使得锁的粒度更低 //所以相比于以前,这里进行了优化,不用锁而是使用了普通的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) { //缓存中已经有了数据就不需要填充进去了,当cache中无数据的时候 //putIfAbsent会返回null,有数据则会返回旧数据而不执行put的操作 newRetriever = null; } } } //缓存中retriever不为null,直接返回retriever的获取监听器方法 if (existingRetriever != null) { Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners(); if (result != null) { return result; } /** 这里会出现缓存中存在检索器,但是监听器为空的情况是因为当另一个线程 设置existingRetriever的时候被感知到了 另一个线程比当前线程调用putIfAbsent方法快一点,参考CurrentHashMap的特点, 所以这个线程可以感知到缓存中已经存在existingRetriever了, 但是另一个线程也是执行到这里,所以并不执行接下来的etrieveApplicationListeners初始化 检索器持有的监听器,而是稍后继续执行,所以导致这里获取到的监听器还是空的, 所以这里的处理是当前线程默认已经把监听器加载进去了, 在下一步方法中通过newRetriever为空 来判断 是否对检索器进行监听器列表的属性的赋值,默认是把已经加载到SpringApplication对象 持有的监听器列表返回(因为另一个线程如果填充也是填充这些) **/ //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 监听器容器对象的初始化

当上面的方法设置好存储监听器的容器后,就到了初始化这个检索器设置事件和对该事件感兴趣的监听器列表的方法了-》retrieveApplicationListeners 方法。


这个阶段主要的问题就是根据广播的事件的类型筛选出哪些监听器需要做出响应,然后把这些监听器以 事件类型加来源:对这个事件感兴趣的监听器列表 的形式存储在 concurrentHashMap 中。


//AbstractApplicationEventMulticasterprivate 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的监听器列表是在SpringApplication创建的时候初始化和赋值 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;}
复制代码


5.3.1 supportsEvent 判断是否支持监听这个事件

观察 supportsEvent 的内部逻辑看看是如何判断哪些监听器对这个事件感兴趣


//AbstractApplicationEventMulticasterprotected boolean supportsEvent(      ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {      //由于supportsEventType方法只支持GenericApplicationListener类型的监听器,所以先使用设配器      //抽取出监听器的声明的指定监听的问题的类型以及监听器的对象,创建一个普通的监听器      //对象 GenericApplicationListener,便于后续对这些不同的监听器采取一样的判断操作      GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?            (GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));      return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));}
复制代码




在调用适配器转换为 GenericApplicationListenerAdapter(继承了 GenericApplicationListener)对象后,通过这个对象调用 supportsEventType 方法和 supportsSourceType 方法


//GenericApplicationListenerAdapter
public GenericApplicationListenerAdapter(ApplicationListener<?> delegate) { Assert.notNull(delegate, "Delegate listener must not be null"); //委托适配的监听器对象 this.delegate = (ApplicationListener<ApplicationEvent>) delegate; //解析该监听器感兴趣的事件类型 //declaredEventType 这个监听器的泛型指定的类型(声明的类型是) this.declaredEventType = resolveDeclaredEventType(this.delegate);}
//解析该监听器感兴趣的事件类型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);}
复制代码


调用设配器转换完后可以知道这个监听器的监听事件类型,以及监听器对象



接下来就是根据适配后的对象调用方法 supportsEventType 和 supportsSourceType 判断这个监听器对该事件感兴趣与否。


public boolean supportsEventType(ResolvableType eventType) {         //根据这个方法的调用方判断这个对象的类别(通过之前的Adapter适配后设置或者原本就有的delegate来判断)    if (this.delegate instanceof GenericApplicationListener) {            //为真则调用这个对象的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 {            //不为真则根据这个监听器监听的事件类型declaredEventType和传进来的时间类型eventType相匹配,返回这个判断结果            //declaredEventType为空则说明这个监听器没有设置监听的事件类型,则监听所有的事件,返回true            //不为空则对比声明的监听类型是否和传递进来的事件类型是否一致      return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));    }}
复制代码


这里有一个疑问为啥要单独分开 supportsEventType 判断,最后分支的 else 不适配特定类型的监听器?当 smartListener.supportsEventType(eventType)为真的时候则进行事件来源的判断


//GenericApplicationListenerAdapter
public boolean supportsSourceType(@Nullable Class<?> sourceType) { //假如这个不是SmartApplicationListener的子类(GenericApplicationListener是SmartApplicationListener的子类)则为true, //而如果是属于SmartApplicationListener的子类则再调用SmartApplicationListener对象的supportsSourceType方法 return !(this.delegate instanceof SmartApplicationListener) || ((SmartApplicationListener) this.delegate).supportsSourceType(sourceType);}
复制代码


当检测出这个监听器对这个事件有监听的话就添加进监听器列表


//AbstractApplicationEventMulticaster
for (ApplicationListener<?> listener : listeners) { if (supportsEvent(listener, eventType, sourceType)) { if (retriever != null) { filteredListeners.add(listener); } allListeners.add(listener); }}
复制代码


最后按照事件类型加来源 - 》 监听器列表放到 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;
复制代码


六、监听器对事件做出响应我们回到广播器的广播方法


//SimpleApplicationEventMulticaster
//该方法主要用于根据事件的类型,获取到对这个事件感兴趣的监听器,然后调用监听器的监听方法onApplication执行对应的事件响应逻辑public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); Executor executor = getTaskExecutor(); //getApplicationListeners 获取对这个事件感兴趣的监听器 for (ApplicationListener<?> listener : getApplicationListeners(event, type)) { if (executor != null) { executor.execute(() -> invokeListener(listener, event)); } else { //调用这些监听器的onApplication方法对这个事件做出响应 invokeListener(listener, event); } }}
复制代码


我们通过以上的方法已经找到了对这个事件感兴趣的监听器列表,之后就是遍历这些监听器,然后分别调用这些监听器的对应的响应的方法 onApplication


我们看 invokerListener 方法


public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {    //调用这些监听器的onApplication方法对这个事件做出响应    invokeListener(listener, event);}
复制代码


这个方法传入了需要调用的监听器,以及事件对象


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) 是主动调用了这个监听器的响应方法的。

七、总结

通过该监听器的加载流程中了解到 SPI 的加载这种方式的便利性,简化了 xml 配置,为注解编程提供了切入点;同时从广播器调度器这种设计思想,通过封装广播方法从而简化调用者发布事件,降低耦合度,以及适配器的使用,SpringBoot 中的事件发布机制。


八、参考链接

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

发布于: 10 小时前阅读数: 9
用户头像

还未添加个人签名 2021.04.27 加入

还未添加个人简介

评论

发布
暂无评论
SpringBoot启动加载监听器以及监听应用启动阶段事件