本文基于:spring-boot-2.3.12-RELEASE、spring-cloud-Hoxton.SR12(即2.2.9-RELEASE)
Springboot的SpringApplication事件监听是独立于spring容器事件管理的另一套机制,分为:
starting、environmentPrepared、contextPrepared、contextLoaded、started、running、failed等应用阶段的监听
springboot启动的核心方法:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
// @A
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
...省略...
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
@A:初步看来,spring-boot使用了 SpringApplicationRunListeners 这个类来抽象了spring应用运行时的一些event;SpringApplicationRunListeners 实则是对SpringApplicationRunListener子类集合的封装
SpringApplication构造方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// @A
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// @B
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
@A、@B:在这里我先讲SpringApplication的构造方法,是因为在构造方法里做了很多事情,跟本文有关的就是框架会在构造方法里从配置文件spring.factories里拿到key为org.springframework.context.ApplicationListener 和 key为org.springframework.context.ApplicationContextInitializer的类,实例化好后缓存起来
这一点很重要,否则后面看代码会很绕;getSpringFactoriesInstances方法源码如下
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
// @A
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
@A:解析配置文件并实例化,返回对象
SpringApplicationRunListeners 初始化
在调用spring-boot SpringApplication的run方法流程中,有一行代码: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));
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
// @A
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// @B
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
@A:这个方法会到 spring.factories 文件里去拿 org.springframework.boot.SpringApplicationRunListener 为key 的value值
@B:创建对应的实例集合,框架默认为SpringApplicationRunListener提供了一个子类 EventPublishingRunListener,所以instances的size是1
EventPublishingRunListener
我们来看看其构造方法
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
// @A
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
@A:将application里的Listeners加载到自己类中,那么这些Listeners从哪里来的呢?
这就跟上面的 SpringApplication 构造方法有关了,在构造方法里已经将这些listeners提前加载了!(我反正是debug了一大圈才发现!)
这就完成了 EventPublishingRunListener 对象的初始化,后面springapplication的事件体系都由这个类来管控了!
扩展点:spring cloud 就是扩展了 org.springframework.context.ApplicationListener 实现了双容器!下一篇再详细分析一下双容器。
over~~