SpringApplicationRunListeners与ApplicationListener生命周期分析

SpringApplicationRunListeners负责在SpringBoot启动的不同阶段, 广播出不同的消息, 传递给ApplicationListener监听器实现类。
它的实例化和调用都在SpringApplication.run方法中。

下面分析SpringApplicationRunListeners的创建与执行过程

1. SpringApplicationRunListeners的创建和类结构说明

1.1 SpringApplicationRunListeners的创建

   该类的实例化位于SpringApplication第291行, run方法中:

  291:SpringApplicationRunListeners listeners = getRunListeners(args);

  

   [代码块-方法定义(getRunListeners)]:

private SpringApplicationRunListeners getRunListeners(String[] args) {
    Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
    return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
            SpringApplicationRunListener.class, types, this, args));
}

SpringApplicationRunListeners通过new构造而来, 构造器接收两个参数, (Log log, Collection<? extends SpringApplicationRunListener> listeners)
保存到全局变量log, listeners中.

[类图-SpringApplicationRunListeners]

SpringApplicationRunListeners虽然没实现SpringApplicationRunListener接口, 但是方法命名与SpringApplicationRunListener接口保持了一致,
调用SpringApplicationRunListeners中的方法, 实际就是循环调用listeners同名方法.

 

1.2 listeners的创建

 listeners通过代码 [代码块-方法定义(getRunListeners)] 中的 getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args) 创建.

 getSpringFactoriesInstances方法在很多地方都有调用, 它通过读取META-INF/spring.factories文件, 获取指定类型的Class信息, 创建并返回。
 这里用的getSpringFactoriesInstances实现定义为:

 

/**
* SpringApplication.java  第386行
* 从classpath的META-INF/spring.factories文件中, 读取符合type类型的class定义, 实例化并返回
* @param type 需要读取的类型
* @param parameterTypes type的构造器对应的参数类型列表
* @param args type的构造器对应的参数值
*/
getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args)

这里的listeners即SpringApplicationRunListener的子类.

Tips: SpringApplicationRunListener仅有一个实现类: EventPublishingRunListener, 在spring-boot-1.5.9.RELEASE.jar 的 META-INF/spring.factories中会被读取到

       

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

最终通过反射API, 调用

[代码块-构造器EventPublishingRunListener]

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

创建出EventPublishingRunListener示例, 可以看到构造器参数与[代码块-方法定义(getRunListeners)]中types声明的一致. application就是SpringApplication启动类的实例.

EventPublishingRunListener是一个事件发布器, 它构造出不同的Event, 通过initialMulticaster广播出去,
EventPublishingRunListener将application中的listeners添加进了initialMulticaster.defaultRetriever.applicationListeners中, 依赖关系比较长, 通过类图稍直观一点
[类图-EventPublishingRunListener]

SimpleApplicationEventMulticaster中对listeners做了一个Map缓存retrieverCache,

key = new ListenerCacheKey(eventType, sourceType); // 事件类型+事件源
value = new ListenerRetriever(true);    // ListenerRetriever中保存了Set<ApplicationListener<?>> applicationListeners, 它使用LinkHashSet结构存储, 保证了存入时的顺序

当EventPublishingRunListener触发相同事件时, 可以直接从缓存中获得监听器列表.

创建后的SpringApplicationRunListeners对象:
[图片-SpringApplicationRunListeners实例]

 

其中, EventPublishingRunListener实例:
[图片-EventPublishingRunListener实例]

Tips:
上文中提到的: 调用SpringApplicationRunListeners中的方法, 实际就是循环调用listeners同名方法
一般情况下, 这句话可以更直观的说成: 调用SpringApplicationRunListeners中的方法, 实际就是调用EventPublishingRunListener同名方法

 

2. SpringApplicationRunListeners事件触发

2.1 事件触发时机

    SpringApplication.run方法中:

292:listeners.starting();    // 应用启动时, event: new ApplicationStartedEvent(this.application, this.args)
296:ConfigurableEnvironment environment = prepareEnvironment(listeners, 
                    applicationArguments);
                    325:listeners.environmentPrepared(environment); // 环境预处理, event: new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment)
301:prepareContext(context, environment, listeners, applicationArguments,    
                    printedBanner);
                    339:listeners.contextPrepared(context);    // ApplicationContext上下文预处理, 无事件发布
                    ...
                    356:listeners.contextLoaded(context);// ApplicationContext上下文加载完成, event: new ApplicationPreparedEvent(this.application, this.args, context)
                    ...
305:listeners.finished(context, null);    // ApplicationContext上下文初始化完成, event: new ApplicationReadyEvent(this.application, this.args, context)
2.2 调用规则

2.1中SpringApplicationRunListeners的方法调用基本一样, 都是循环调用listeners, EventPublishingRunListener中的同名方法, 例如starting: 

for (SpringApplicationRunListener listener : this.listeners) {
    listener.starting();
}

最终调用到ApplicationListener, 见[类图-EventPublishingRunListener]

[图片-EventPublishingRunListener实例]中可以看到listners有10个, 执行过程中, 不同事件源\事件, 监听器列表可能会不一样.

转载于:https://www.cnblogs.com/javale/p/8658829.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值