Spring Boot 源码研读之执行SpringApplicationRunListener.starting()
源码分析void starting(ConfigurableBootstrapContext bootstrapContext, Class? mainApplicationClass) { doWithListeners(spring.boot.application.starting, (listener) - listener.starting(bootstrapContext), (step) - { if (mainApplicationClass ! null) { step.tag(mainApplicationClass, mainApplicationClass.getName()); } }); } //.... private void doWithListeners(String stepName, ConsumerSpringApplicationRunListener listenerAction, ConsumerStartupStep stepAction) { StartupStep step this.applicationStartup.start(stepName); this.listeners.forEach(listenerAction); if (stepAction ! null) { stepAction.accept(step); } step.end(); }通过上面代码可以看出核心逻辑就一行代码this.listeners.forEach(listenerAction);即通过λ表达式的方式去执行SpringApplicationRunListener实现类的starting()方法入参是ConfigurableBootstrapContext对象即为 Spring Boot 源码研读之创建DefaultBootstrapContext并执行BootstrapRegistryInitializer.initialize()-CSDN博客 中创建的DefaultBootstrapContext对象。而通过SpringFactoriesLoader加载的SpringApplicationRunListener实现类只有一个EventPublishingRunListener。EventPublishingRunListener类的主要作用的是将生命周期的每个操作包装成一个对应的ApplicationEvent事件并通过SimpleApplicationEventMulticaster去多播执行所有的ApplicationListener实现类的onApplicationEvent()方法。注意这里会根据传入的事件类型进行过滤即传入的事件类型是否与ApplicationListener实现类onApplicationEvent()方法参数的事件类型一致如果不一致会被过滤掉。注意事件类型的判断也可以在onApplicationEvent()方法的内部判断即实现类onApplicationEvent()方法参数类型为抽象类ApplicationEvent。多播事件前的刷新ApplicationListenerprivate void refreshApplicationListeners() { this.application.getListeners().forEach(this.initialMulticaster::addApplicationListener); }Override public void addApplicationListener(ApplicationListener? listener) { synchronized (this.defaultRetriever) { // Explicitly remove target for a proxy, if registered already, // in order to avoid double invocations of the same listener. Object singletonTarget AopProxyUtils.getSingletonTarget(listener); if (singletonTarget instanceof ApplicationListener) { this.defaultRetriever.applicationListeners.remove(singletonTarget); } this.defaultRetriever.applicationListeners.add(listener); this.retrieverCache.clear(); } }目的是将应用配置中的listeners注册到广播器中避免有遗漏或者后续新添加同时还进行了aop代理去重避免了listener的重复调用。上下文加载完毕时的特殊处理Override public void contextLoaded(ConfigurableApplicationContext context) { for (ApplicationListener? listener : this.application.getListeners()) { if (listener instanceof ApplicationContextAware contextAware) { contextAware.setApplicationContext(context); } context.addApplicationListener(listener); } multicastInitialEvent(new ApplicationPreparedEvent(this.application, this.args, context)); }在上下文加载完毕广播ApplicationPreparedEvent事件前会对实现了ApplicationContextAware接口的listener进行上下文填充同时将listener添加到Spring容器的广播器中这样容器便有了广播事件的能力。我们可以看到在后续的 started、ready、failed 节点时广播事件都是通过spring 容器广播的。总结一下SpringApplicationRunListener定义了 Spring boot 应用生命周期各阶段的方法包含starting、environmentPrepared、contextPrepared、contextLoaded、started、ready、failedEventPublishingRunListener实现了SpringApplicationRunListener生命周期方法内部通过SimpleApplicationEventMulticaster事件广播器广播执行实现了对应事件的ApplicationListener。ApplicationListener实现类是具体的事件实现者用户可以自定义实现类并结合Spring内置的事件以便在其生命周期各个阶段做一些额外的操作。注spring boot 版本为3.2.3