springboot源码分析14-事件发布机制以及应用监听器

摘要:事件驱动模型,也就是我们经常提到用到的观察者模式。当然也可以将其理解为发布-订阅模型。具体的实现要素有如下几个方面。

1、首先是一对多的关系,一是目标对象,多则是观察者对象。比如报社是一个,而订报者是多个。

2、当目标对象的行为发生变化的时候,多个观察者对象会级联触发并做出相应的处理。换言之,目标对象的行为发生变化的时候,只需要通知一下所有的观察者对象(订阅过的)即可。具体的各个观察者怎么去处理,使用什么方式去处理,并不是目标对象所需要考虑的范畴。也就是说目标与观察者的实现是低耦合。目标对象的职责就是去通知各个观察者,各个观察者的职责是具体做事情的。大家各司其职协调工作。

3、目标对象怎么能在自身状态发生变化的时候,去实时通知到各个观察者呢?无外乎就是如下的两种思路。

实现方案1:

     所有需要通知的观察者去目标对象中注册登记,当目标对象需要通知的时候,查询登记列表中的所有观察者,然后一个个的下发。

实现方案2:

所有需要通知的观察者去目标对象中注册登记,登记的时候告诉目标对象自己需要监听的事件类型,只有是自己注册的事件变化时,才接受通知,否则目标对象的其他事件不要通知这个观察者。

上述的两个方案,方案1强调的是目标对象只要发生行为状态改变,所有的观察者都可以收到通知,并自行处理。方案2有点类似精准投递,比如观察者对象1只监听a事件,那么当目标对象触发b事件的时候不需要通知观察者对象1。两种方案各有优缺点,我个人倾向使用方案2。因为该方案可以根据不同的事件源去通知不同的观察者。

了解了上述的内容之后,接下来我们看一下Springboot中所使用的事件发布机制以及ApplicationListener。

1.1. SpringApplicationRunListener

我们一步到位,直接定位到SpringApplication类中的run方法,相关实现代码如下:

public ConfigurableApplicationContext run(String... args) {

...

SpringApplicationRunListeners listeners = getRunListeners(args);

listeners.starting();

...

}

我们重点看一下getRunListeners方法的处理逻辑,该方法的实例代码如下:

private SpringApplicationRunListeners getRunListeners(String[] args) {

Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };

return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(

pringApplicationRunListener.class, types, this, args));

}

首先看一下getSpringFactoriesInstances方法,代码如下:

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,

Class<?>[] parameterTypes, Object... args) {

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

Set<String> names = new LinkedHashSet<>(

SpringFactoriesLoader.loadFactoryNames(type, classLoader));

List<T> instances = createSpringFactoriesInstances(type, parameterTypes,

classLoader, args, names);

AnnotationAwareOrderComparator.sort(instances);//order值越小,越靠前

return instances;

}

上述的代码,前面的系列文章也详细讲解过,就是查询所有META-INF/spring.factories配置文件中key为org.springframework.boot.SpringApplicationRunListener的值,我们找一下spring-boot-2.0.0.M7.jar中的META-INF/spring.factories配置文件,相关配置如下所示:

# Run Listeners

org.springframework.boot.SpringApplicationRunListener=\

org.springframework.boot.context.event.EventPublishingRunListener

因此上述代码执行完毕之后。会通过反射实例化EventPublishingRunListener类,该类的构造函数如下:

private final SimpleApplicationEventMulticaster initialMulticaster;

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);

}

}

首先,实例化SimpleApplicationEventMulticaster类,然后调用application对象中的getListeners()方法,并循环将该函数的返回值集合添加到initialMulticaster中。initialMulticaster我们可以将其理解为事件发布器。getListeners()方法中返回的集合在哪里初始化的呢?我们继续回到SpringApplication类的构造函数中。如下所示:

private List<ApplicationListener<?>> listeners;

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {

...

setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

}

public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {

this.listeners = new ArrayList<>();

this.listeners.addAll(listeners);

}

SpringApplication类的构造函数中,也就直接通过getSpringFactoriesInstances方法直接获取到META-INF/spring.factories配置文件中key为org.springframework.context.ApplicationListener的值,我们找一下spring-boot-2.0.0.M7.jar中的META-INF/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.ConfigFileApplicationListener,\

org.springframework.boot.context.config.DelegatingApplicationListener,\

org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\

org.springframework.boot.context.logging.LoggingApplicationListener,\

org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

上述的13个监听类均是监听不同的事件进行处理的,我们也可以自定义一些监听器进行业务处理,添加方式如下所示:

SpringApplication springApplication = new SpringApplication(DemoApplication.class);

   springApplication.addListeners(new ShareniuApplicationListener());

通过上述代码我们可以看出,所有的事件监听器最终存储在SpringApplication类中的listeners集合中。

1.2. Springboot中事件的发布以及监听

接下来,我们来看一下Springboot中事件的发布以及监听。我们继续回归到listeners.starting()方法中。

public void starting() {

for (SpringApplicationRunListener listener : this.listeners) {

listener.starting();

}

}

循环遍历所有的listeners,并依此调用listeners中的starting方法。

注意:listeners是SpringApplicationRunListener类型,并非是ApplicationListener类型,这点一定不要搞混淆了。SpringApplicationRunListener中持有所有的ApplicationListener类型监听器集合。EventPublishingRunListener类中的starting方法代码如下:

public void starting() {

this.initialMulticaster.multicastEvent(

new ApplicationStartingEvent(this.application, this.args));

}

注意这里产生的事件是ApplicationStartingEvent类型,因此只有监听到ApplicationStartingEvent事件的监听器才可以观察到进而进行自己的处理。this.initialMulticaster.multicastEvent方法实现如下:

public void multicastEvent(ApplicationEvent event) {

multicastEvent(event, resolveDefaultEventType(event));

}

public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {

ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));

for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {

Executor executor = getTaskExecutor();

if (executor != null) {

executor.execute(() -> invokeListener(listener, event));

}

else {

invokeListener(listener, event);

}

}

}

在构造ApplicationStartedEvent时传给它的基类EventObjectprotected不可序列化属性source。实例化ApplicationStartedEventinstance.getClass()并包装为ResolvableType类型以保存类型信息,并将它和event作为参数传入SimpleApplicationEventMulticastermulticastEvent方法。multicastEvent首先获取ApplicationListener,使用getApplicationListeners方法,这个方法中抛开对listener做了一些缓存类工作外,主要就是将事件和对应的监听器做了下是否支持的验证,返回通过了retrieveApplicationListeners中通过了supportsEvent验证的监听器集合,这里就体现出了ResolvableType的作用,它保存了类型的信息同时对泛型类型也支持。

在整个SpringBoot启动的过程中,会先后出产生如下的几个事件。

ApplicationStartingEvent-->>ApplicationEnvironmentPreparedEvent-->>ApplicationPreparedEvent

ContextRefreshedEvent-->>ApplicationReadyEvent-->>ContextClosedEvent

后续的系列文章,我们对于核心的监听器一个个进行讲解,从而加深印象。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值