SpringBoot:SpringBoot启动过程中这些事件你必须掌握

一、前言

  在Spring Boot的启动过程中,会触发一系列的事件,这些事件为开发者提供了在特定阶段扩展系统功能的机会。本文将介绍Spring Boot的启动过程中的一些事件,以及知道这些事件,我们能做什么。

二、启动过程中的事件以及作用

1. ApplicationStartingEvent:
  触发时机:在Spring Boot应用程序启动的最早阶段触发。
  用途:此时,应用程序刚刚启动,可能正在加载配置文件和设置。

源码

	@Override
	public void starting() {
		this.initialMulticaster.multicastEvent(
				new ApplicationStartingEvent(this.application, this.args));
	}

作用
  在这个阶段,你可以进行日志初始化、系统参数设置等准备工作。

import org.springframework.boot.context.event.ApplicationStartingEvent;  
import org.springframework.context.ApplicationListener;  
  
public class ApplicationStartingEventListener implements ApplicationListener<ApplicationStartingEvent> {  
  
    @Override  
    public void onApplicationEvent(ApplicationStartingEvent event) {  
        // 在这里进行日志初始化、系统参数设置等操作  
        System.out.println("Application is starting...");  
    }  
}  
  
// 注册监听器  
// 通常通过Spring的组件扫描自动注册,或者使用@Bean在配置类中注册

2. ApplicationEnvironmentPreparedEvent:
  触发时机:在Environment对象创建之后,Context对象创建之前抛出。
  用途:此时,应用程序的环境已经准备好,但Spring上下文还未被创建和初始化。

源码

@Override
	public void environmentPrepared(ConfigurableEnvironment environment) {
		this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
				this.application, this.args, environment));
	}

作用
  你可以在这个阶段访问和修改应用程序的环境属性

import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;  
import org.springframework.context.ApplicationListener;  
import org.springframework.core.env.ConfigurableEnvironment;  
  
public class ApplicationEnvironmentPreparedEventListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {  
  
    @Override  
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {  
        ConfigurableEnvironment environment = event.getEnvironment();  
        // 在这里访问和修改环境属性  
        String customProperty = environment.getProperty("custom.property");  
        System.out.println("Custom property: " + customProperty);  
        // ...  
    }  
}

3. ApplicationContextInitializedEvent:
  触发时机:在ApplicationContext对象被初始化后抛出,但所有bean的定义还没被加载。
  用途:允许在bean定义加载之前对ApplicationContext进行初始化操作。

源码

private void prepareContext(ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
		context.setEnvironment(environment);
		postProcessApplicationContext(context);
		applyInitializers(context);
		
	    // 触发ApplicationContextInitializedEvent事件
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		// Load the sources
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		load(context, sources.toArray(new Object[0]));
		listeners.contextLoaded(context);
	}

应用
  假设我们想在 ApplicationContext 初始化时,基于 Environment 的某些属性来动态注册一些 BeanDefinition。

import org.springframework.context.ApplicationContextInitializer;  
import org.springframework.context.ConfigurableApplicationContext;  
import org.springframework.core.env.ConfigurableEnvironment;  
  
public class CustomApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {  
  
    @Override  
    public void initialize(ConfigurableApplicationContext applicationContext) {  
        ConfigurableEnvironment environment = applicationContext.getEnvironment();  
  
        // 假设我们有一个名为 custom.feature.enabled 的属性  
        String featureEnabled = environment.getProperty("custom.feature.enabled");  
  
        if ("true".equals(featureEnabled)) {  
            // 基于该属性,我们可以动态地注册一个 bean 到 Spring 上下文中  
            // 这里只是一个示例,实际上你需要使用 BeanDefinitionRegistry 来注册 bean  
            // ...  
  
            // 另一种选择是设置一些属性或执行其他初始化任务  
            System.out.println("Custom feature is enabled. Performing additional initialization...");  
        }  
    }  
}

4. ApplicationPreparedEvent:
  触发时机:在bean定义被加载之后,Context对象刷新之前抛出。
  用途:此时,Spring的bean定义已经加载,但Spring上下文还未完全初始化。

源码

private void prepareContext(ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
		context.setEnvironment(environment);
		postProcessApplicationContext(context);
		applyInitializers(context);
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		// Load the sources
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		load(context, sources.toArray(new Object[0]));
		// 触发事件
		listeners.contextLoaded(context);
	}

应用

@Component  
public class ApplicationPreparedEventListener implements ApplicationListener<ApplicationPreparedEvent> {  
  
    @Override  
    public void onApplicationEvent(ApplicationPreparedEvent event) {  
        System.out.println("ApplicationPreparedEvent触发:ApplicationContext已创建,但bean还未加载。");  
        ConfigurableApplicationContext applicationContext = event.getApplicationContext();  
        // 在这里可以向ApplicationContext中添加自定义的bean定义  
    }  
}

5.ServletWebServerInitializedEvent:
  触发时机:当内嵌的Servlet Web服务器初始化完成时触发。
  用途:获取关于Web服务器的信息,例如监听端口等。

源码

@Override
	protected void finishRefresh() {
		super.finishRefresh();
		WebServer webServer = startWebServer();
		if (webServer != null) {
			publishEvent(new ServletWebServerInitializedEvent(webServer, this));
		}
	}

应用

@Component  
public class ServletWebServerInitializedEventListener implements ApplicationListener<ServletWebServerInitializedEvent> {  
  
    @Override  
    public void onApplicationEvent(ServletWebServerInitializedEvent event) {  
        System.out.println("ServletWebServerInitializedEvent触发:内嵌Web服务器已初始化完成。");  
        WebServer webServer = event.getWebServer();  
        int port = webServer.getPort();  
        // 在这里可以获取Web服务器的端口号、设置HTTP监听器等  
    }  
}

6. ContextRefreshedEvent:
  触发时机:在ApplicationContext被初始化或刷新时触发。
  用途:这通常意味着所有的bean都已经加载,并且可以进行后处理操作。

源码

	protected void finishRefresh() {
		// Clear context-level resource caches (such as ASM metadata from scanning).
		clearResourceCaches();

		// Initialize lifecycle processor for this context.
		initLifecycleProcessor();

		// Propagate refresh to lifecycle processor first.
		getLifecycleProcessor().onRefresh();

		// Publish the final event.
		publishEvent(new ContextRefreshedEvent(this));

		// Participate in LiveBeansView MBean, if active.
		LiveBeansView.registerApplicationContext(this);
	}

应用
  假设我们有一个需要在 Spring 容器初始化后执行的操作,比如加载一些静态数据到缓存中。我们可以创建一个监听 ContextRefreshedEvent 的类,并在该类中执行我们需要的操作。

import org.springframework.context.ApplicationContext;  
import org.springframework.context.ApplicationListener;  
import org.springframework.context.event.ContextRefreshedEvent;  
  
public class MyContextRefreshedListener implements ApplicationListener<ContextRefreshedEvent> {  
  
    @Override  
    public void onApplicationEvent(ContextRefreshedEvent event) {  
        ApplicationContext applicationContext = event.getApplicationContext();  
  
        // 在这里执行你需要的操作,比如加载数据到缓存  
        System.out.println("ContextRefreshedEvent received. Loading data into cache...");  
  
        // 假设我们有一个服务,用于加载数据到缓存  
        MyDataService myDataService = applicationContext.getBean(MyDataService.class);  
        myDataService.loadDataToCache();  
    }  
}

7. ApplicationStartedEvent:
  触发时机:在Context对象刷新之后,应用启动器被调用之前抛出。
  用途:此时,应用程序已经启动,但还未准备好接收HTTP请求。

源码

public ConfigurableApplicationContext run(String... args) {
	...
		
	refreshContext(context);
	// 容器已经初始化完成,发布该事件		
	listeners.started(context);
		
	return context;
	}

应用
  假设我们想在 Spring Boot 应用程序启动后执行一些自定义的初始化操作,比如启动一个后台任务。我们可以创建一个监听 ApplicationStartedEvent 的类,并在该类中执行我们需要的操作

import org.springframework.boot.context.event.ApplicationStartedEvent;  
import org.springframework.context.ApplicationListener;  
  
public class MyApplicationStartedListener implements ApplicationListener<ApplicationStartedEvent> {  
  
    @Override  
    public void onApplicationEvent(ApplicationStartedEvent event) {  
        // 在这里执行你需要的操作,比如启动一个后台任务  
        System.out.println("ApplicationStartedEvent received. Starting background task...");  
  
        // 假设我们有一个服务,用于启动后台任务  
        MyBackgroundTaskService myBackgroundTaskService = new MyBackgroundTaskService();  
        myBackgroundTaskService.start();  
    }  
}

8. ApplicationReadyEvent:
  触发时机:在应用启动器被调用之后抛出,这代表着应用已经被正常的启动,可以接收请求了。
  用途:这是应用程序启动的最后阶段,此时应用程序已经完全准备好,可以开始处理请求。

源码

public ConfigurableApplicationContext run(String... args) {
    // 刷新上下文  
    refreshContext(context);
    try {
      // 触发ApplicationReadyEvent事件
      listeners.ready(context, timeTakenToReady);
    }
  }  

应用

@Component  
public class ApplicationReadyEventListener implements ApplicationListener<ApplicationReadyEvent> {  
  
    @Override  
    public void onApplicationEvent(ApplicationReadyEvent event) {  
        System.out.println("ApplicationReadyEvent触发:Spring Boot应用程序已准备好服务请求。");  
        // 在这里可以执行一些需要在应用程序完全就绪后才能进行的操作  
    }  
}

9.ApplicationFailedEvent:
  触发时机:当应用程序启动失败时触发。
  用途:通知监听器应用程序启动失败,并可能包含关于失败原因的详细信息。

源码

 // 刷新上下文  
    refreshContext(context);
    try {
      // 当这里发生了异常
      listeners.ready(context, timeTakenToReady);
    } catch (Throwable ex) {
      // 发布ApplicationFailedEvent事件
      handleRunFailure(context, ex, null);
      throw new IllegalStateException(ex);
    }

  这些事件是Spring Boot生命周期中的关键节点,允许开发者在特定的时间点执行自定义逻辑,如初始化资源、加载配置、设置监听器等。通过实现ApplicationListener接口并注册相应的监听器,开发者可以监听这些事件并在事件发生时执行特定的操作。

  • 12
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一些关于Spring Boot的常见面试问题及其答案: 1. 什么是Spring BootSpring Boot是一种基于Spring框架的快速开发Web应用程序的框架,它可以帮助开发人员快速搭建Spring应用,并提供了许多开箱即用的功能和插件。 2. Spring Boot的优点是什么? Spring Boot有很多优点,包括: - 快速开发:Spring Boot提供了一些开箱即用的功能和插件,可以让开发人员更快地搭建应用程序。 - 自动配置:Spring Boot会自动配置应用程序,减少了开发人员的工作量。 - 简化配置:Spring Boot提供了一种简化配置的方式,可以方便开发人员进行配置。 - 方便部署:Spring Boot可以打包成一个可执行的JAR文件,方便部署。 3. Spring Boot的核心组件是什么? Spring Boot的核心组件包括: - Spring Framework - Spring MVC - Spring Data - Spring Security 4. Spring Boot启动流程是怎样的? Spring Boot启动流程包括以下几个步骤: - 加载Spring Boot的核心配置文件 - 扫描应用程序的所有组件 - 自动配置Spring应用程序 - 启动Spring应用程序 5. Spring Boot如何处理依赖关系? Spring Boot使用Maven或Gradle来管理依赖关系,开发人员可以通过配置pom.xml或build.gradle文件来管理依赖关系。 6. Spring Boot如何处理多环境配置? Spring Boot可以根据不同的环境加载不同的配置文件,例如application-dev.properties、application-prod.properties等。开发人员可以通过配置文件来管理不同环境下的配置信息。 以上是一些常见的关于Spring Boot的面试问题及其答案,希望能对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值