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信息//打印bannerBanner printedBanner = this.printBanner(environment);//创建应用上下文context = this.createApplicationContext();context.setApplicationStartup(this.applicationStartup);this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);//刷新,就是spring的refreshthis.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
@Overridepublic 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
的: