Spring Boot中的各种事件

spring boot 各种事件贯穿整个启动的生命周期,读懂了这些时间也差不多理解了springboot的启动流程。

SpringApplicationRunListener中的事件

接口org.springframework.boot.SpringApplicationRunListener定义了spring启动过程中各个事件被触发的顶层方法

java 复制代码
public interface SpringApplicationRunListener {
        
        default void starting() {
        }

        
        default void environmentPrepared(ConfigurableEnvironment environment) {
        }
        
        default void contextPrepared(ConfigurableApplicationContext context) {
        }
        
        default void contextLoaded(ConfigurableApplicationContext context) {
        }
        
        default void started(ConfigurableApplicationContext context) {
        }
        
        default void running(ConfigurableApplicationContext context) {
        }
        
        default void failed(ConfigurableApplicationContext context, Throwable exception) {
        }

    }

SpringApplicationRunListener的方法定义很讲究,方法从上到下的顺序也正好是各事件触发的顺序。SpringApplicationRunListener接口的唯一具体实现类是org.springframework.boot.context.event.EventPublishingRunListener

  1. starting接口表示springboot程序准备开始启动,这是最早的事件触发方法,它将触发ApplicationStartingEvent事件。这个事件一般没人关心,目前spring中没有任何逻辑实现依赖于这个事件。
java 复制代码
	//EventPublishingRunListener
	@Override
	public void starting() {
		this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
	}
  1. environmentPrepared接口方法表示Environment对象准备好了,它将触发ApplicationEnvironmentPreparedEvent事件.
java 复制代码
	//EventPublishingRunListener
	@Override
	public void environmentPrepared(ConfigurableEnvironment environment) {
		this.initialMulticaster
				.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
	}

不论是本地配置文件还是云端配置中心,它们的配置内容读取都依赖于此事件。

ConfigFileApplicationListener本地配置文件监听器

java 复制代码
public class ConfigFileApplicationListener implements EnvironmentPostProcessor, SmartApplicationListener, Ordered{
@Override
	public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
		return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)
				|| ApplicationPreparedEvent.class.isAssignableFrom(eventType);
	}

	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		if (event instanceof ApplicationEnvironmentPreparedEvent) {
			onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
		}
		if (event instanceof ApplicationPreparedEvent) {
			onApplicationPreparedEvent(event);
		}
	}
}

BootstrapApplicationListener云端配置中心监听器

java 复制代码
public class BootstrapApplicationListener
		implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {
		
}
  1. contextPrepared表示ApplicationContext实例化后,所有的ApplicationContextInitializer实例的initialize已经被依次调用执行完毕。
    这个方法将触发ApplicationContextInitializedEvent事件
java 复制代码
	//EventPublishingRunListener
	@Override
	public void contextPrepared(ConfigurableApplicationContext context) {
		this.initialMulticaster
				.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
	}
  1. contextLoaded 方法表示ApplicationContext的各种资源已经被读取加载完毕(主要是各种BeanDefination的读取),但还没有进行上下文刷新。此方法将触发ApplicationPreparedEvent事件
java 复制代码
	//EventPublishingRunListener
	@Override
	public void contextLoaded(ConfigurableApplicationContext context) {
		for (ApplicationListener<?> listener : this.application.getListeners()) {
			if (listener instanceof ApplicationContextAware) {
				((ApplicationContextAware) listener).setApplicationContext(context);
			}
			context.addApplicationListener(listener);
		}
		this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
	}
  1. started表示ApplicationContext的refresh刷新完成,但CommandLineRunnersApplicationRunner 这些函数接口还未执行。
java 复制代码
	//EventPublishingRunListener
	@Override
	public void started(ConfigurableApplicationContext context) {
		context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
		AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
	}
  1. running方法表示CommandLineRunnersApplicationRunner函数接口也都被调用执行完毕,它是springboot正常启动过程中的最后一个事件,它标志着项目已完全启动,它将触发ApplicationReadyEvent事件。
java 复制代码
	//EventPublishingRunListener
	@Override
	public void running(ConfigurableApplicationContext context) {
		context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
		AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
	}
  1. failed表示项目启动过程中出现异常,启动过程中的任意一阶段都可能出错。
java 复制代码
	//EventPublishingRunListener
	@Override
	public void failed(ConfigurableApplicationContext context, Throwable exception) {
		ApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception);
		if (context != null && context.isActive()) {
			// Listeners have been registered to the application context so we should
			// use it at this point if we can
			context.publishEvent(event);
		}
		else {
			// An inactive context may not have a multicaster so we use our multicaster to
			// call all of the context's listeners instead
			if (context instanceof AbstractApplicationContext) {
				for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
						.getApplicationListeners()) {
					this.initialMulticaster.addApplicationListener(listener);
				}
			}
			this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
			this.initialMulticaster.multicastEvent(event);
		}
	}

其他事件

ApplicationContext在刷新完成后,生命周期处理器的默认实现类DefaultLifecycleProcessor的onRefresh方法会被调用,并发布ContextRefreshedEvent事件。
DefaultLifecycleProcessor.onRefresh会调用所有实现SmartLifecycle接口的Spring Bean对象的start方法。

java 复制代码
//DefaultLifecycleProcessor

	@Override
	public void onRefresh() {
		startBeans(true);
		this.running = true;
	}
	private void startBeans(boolean autoStartupOnly) {
		Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
		Map<Integer, LifecycleGroup> phases = new HashMap<>();
		lifecycleBeans.forEach((beanName, bean) -> {
			if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
				int phase = getPhase(bean);
				LifecycleGroup group = phases.get(phase);
				if (group == null) {
					group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
					phases.put(phase, group);
				}
				group.add(beanName, bean);
			}
		});
		if (!phases.isEmpty()) {
			List<Integer> keys = new ArrayList<>(phases.keySet());
			Collections.sort(keys);
			for (Integer key : keys) {
				phases.get(key).start();
			}
		}
	}

WebServerStartStopLifecycle也实现了SmartLifecycle接口,此start方法将启动Tomcat容器,并发布ServletWebServerInitializedEvent事件。

相关推荐
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭2 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
AskHarries5 小时前
Spring Cloud OpenFeign快速入门demo
spring boot·后端
isolusion6 小时前
Springboot的创建方式
java·spring boot·后端
Yvemil76 小时前
《开启微服务之旅:Spring Boot Web开发举例》(一)
前端·spring boot·微服务
星河梦瑾7 小时前
SpringBoot相关漏洞学习资料
java·经验分享·spring boot·安全
计算机学长felix9 小时前
基于SpringBoot的“交流互动系统”的设计与实现(源码+数据库+文档+PPT)
spring boot·毕业设计
.生产的驴9 小时前
SpringBoot 对接第三方登录 手机号登录 手机号验证 微信小程序登录 结合Redis SaToken
java·spring boot·redis·后端·缓存·微信小程序·maven
顽疲9 小时前
springboot vue 会员收银系统 含源码 开发流程
vue.js·spring boot·后端
撒呼呼9 小时前
# 起步专用 - 哔哩哔哩全模块超还原设计!(内含接口文档、数据库设计)
数据库·spring boot·spring·mvc·springboot
因我你好久不见9 小时前
springboot java ffmpeg 视频压缩、提取视频帧图片、获取视频分辨率
java·spring boot·ffmpeg