SpringBoot 源码分析 - SpringApplication启动流程三
- 初始化基本流程
- SpringApplication的setListeners设置监听器
- deduceMainApplicationClass对端主启动类
- run
- getRunListeners获取SpringApplicationRunListener监听器
- EventPublishingRunListener的构造方法
- SimpleApplicationEventMulticaster的注册监听器细节
- SpringApplicationRunListeners的starting广播启动事件
初始化基本流程
SpringApplication的setListeners设置监听器
这个跟前面的设置初始化器类似,只是要的类型是org.springframework.context.ApplicationListener
。这个监听器干嘛用,其实就是有个观察者模式,spring
为了让其他可以扩展,让他们知道现在初始化到哪个阶段了,他们可以参数,于是让他们注册到spring
内部,再各个阶段进行通知,这样他们就可以一起初始化了。
public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
this.listeners = new ArrayList(listeners);
}
deduceMainApplicationClass对端主启动类
这里就是推断启动类的,直接抛出异常,然后找到main
方法所在的类。
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = (new RuntimeException()).getStackTrace();
StackTraceElement[] var2 = stackTrace;
int var3 = stackTrace.length;
for(int var4 = 0; var4 < var3; ++var4) {
StackTraceElement stackTraceElement = var2[var4];
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
} catch (ClassNotFoundException var6) {
}
return null;
}
至此SpringApplication
构造方法分析完了,具体做了什么事情,就是初始化类和监听器的创建。接下来分析 run
了。
run
其实就是给上下文做准备,会调用spring
的初始化,会进行不同初始化阶段的广播,去通知监听器,监听器就可以做一些扩展的事情啦,比如初始化自己的环境什么的。
public ConfigurableApplicationContext run(String... args) {
long startTime = System.nanoTime();
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
ConfigurableApplicationContext context = null;
this.configureHeadlessProperty();
获取监听器
SpringApplicationRunListeners listeners = this.getRunListeners(args);
//广播启动事件
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
this.configureIgnoreBeanInfo(environment); //配置要忽略的bean信息
//打印banner
Banner printedBanner = this.printBanner(environment);
//创建应用上下文
context = this.createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//刷新,就是spring的refresh
this.refreshContext(context);
//刷新后处理
this.afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
}
//广播启动完成事件
listeners.started(context, timeTakenToStartup);
//广播运行中事件
this.callRunners(context, applicationArguments);
} catch (Throwable var12) {
this.handleRunFailure(context, var12, listeners);
throw new IllegalStateException(var12);
}
try {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
return context;
} catch (Throwable var11) {
this.handleRunFailure(context, var11, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var11);
}
}
getRunListeners获取SpringApplicationRunListener监听器
这个跟前面的获取方法一样的,获取SpringApplicationRunListener
类型的监听器,但是这个时候有缓存了,因为前面全加载进来啦:
private SpringApplicationRunListeners getRunListeners(String[] args) {
//给EventPublishingRunListener准备的构造方法参数类型,这样后面实例化的时候就可以传参数了
Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup);
}
其实你可以看到,其实是一个事件发布监听器,他的事情就是监听SpringApplication的运行事件,然后发布给其他的监听器,他里面有一个事件广播器的,可以广播给其他监听器事件。
实例化的时候根据参数调用构造方法:
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) {
List<T> instances = new ArrayList(names.size());
Iterator var7 = names.iterator();
while(var7.hasNext()) {
String name = (String)var7.next();
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
T instance = BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
} catch (Throwable var12) {
throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, var12);
}
}
return instances;
}
EventPublishingRunListener的构造方法
这里是有参数传进去的,这样他就能获取所有的监听器,然后创建一个事件广播SimpleApplicationEventMulticaster
,把监听器都注册进去。
org.springframework.boot.context.event.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);
}
}
SimpleApplicationEventMulticaster的注册监听器细节
注册的时候有个细节,他会把代理类型的监听器剔除,防止重复通知,还会清除事件和监听器映射的缓存,因为:
org.springframework.context.event.AbstractApplicationEventMulticaster
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.defaultRetriever) {
//如果已注册代理,则显式删除目标
//以避免对同一侦听器的双重调用。
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
最后封装到SpringApplicationRunListeners
中。
SpringApplicationRunListeners的starting广播启动事件
调用每一个SpringApplicationRunListener的starting
,其实就是调用EventPublishingRunListener
的,因为现在只有一个。
void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
(step) -> {
if (mainApplicationClass != null) {
step.tag("mainApplicationClass", mainApplicationClass.getName());
}
});
}
这个事件继承JDK
里的EventObject
的: