博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringApplicationRunListeners与ApplicationListener生命周期分析
阅读量:6336 次
发布时间:2019-06-22

本文共 4767 字,大约阅读时间需要 15 分钟。

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
type, Class
[] parameterTypes, Object... args)

这里的listeners即SpringApplicationRunListener的子类.

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

       

# Run Listenersorg.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
> 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

你可能感兴趣的文章
SQL some any all
查看>>
电子书下载:Programming Windows Identity Foundation
查看>>
有理想的程序员必须知道的15件事
查看>>
用于测试的字符串
查看>>
财付通和支付宝资料收集
查看>>
PHPCMS V9数据库表结构分析
查看>>
理解 IEnumerable 与 IEnumerator
查看>>
NHibernate 2.0 Beta 1 Released和一些工具
查看>>
【每天一个Linux命令】12. Linux中which命令的用法
查看>>
软件接口数据一致性机制
查看>>
微服务架构介绍和RPC框架对比
查看>>
Debian下使用OpenLDAP 管理端
查看>>
泛型排序器TComparer
查看>>
9个offer,12家公司,35场面试,从微软到谷歌,应届计算机毕业生的2012求职之路...
查看>>
创建符合标准的、有语意的HTML页面——ASP.NET 2.0 CSS Friendly Control Adapters 1.0发布...
查看>>
Adobe驳斥Flash过度耗电论 称HTML5更耗电
查看>>
No!No!No! It's not fashion!
查看>>
艰困之道中学到的经验教训
查看>>
互联网生态建设落地五大挑战——保险科技生态建设 ...
查看>>
进行短视频app开发工作时,可以加入它来保护青少年 ...
查看>>