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

本文共 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

你可能感兴趣的文章
presto中的名词
查看>>
【致青春】开垦出的IT路
查看>>
解决apache服务器下载.dmg文件乱码页码问题
查看>>
四种方案解决ScrollView嵌套ListView问题
查看>>
实例讲解PAT配置
查看>>
centos下network和NetworkManager冲突的解决方法
查看>>
Mac OS上搭建Apache+PHP+MySQL开发环境的详细教程
查看>>
ccnp大型企业综合案例分析2
查看>>
odoo二次开发小知识点
查看>>
linux基础命令 rm
查看>>
多线程 -线程面试题(一)
查看>>
OpenStack如何实现高可用集群介绍
查看>>
Java基础学习总结(1)——equals方法
查看>>
cvLoadImage报错
查看>>
ubuntu chromium字体发虚的解决方法及字体美化
查看>>
mysql
查看>>
Android小技巧—查看代码混淆后的日志
查看>>
用js实现读取出字符串中每个字符重复出现的次数?
查看>>
xcache的使用与配置
查看>>
msysGit管理GitHub代码
查看>>