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(Classtype, 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个, 执行过程中, 不同事件源\事件, 监听器列表可能会不一样.