Spring Boot的启动过程实际上是相当复杂的,涉及大量的组件、自动配置和钩子。下面是一个更加详细的列表,描述了Spring Boot启动时会发生的主要步骤:
-
启动入口:Spring Boot应用的启动从
main
方法开始,通常在这个方法里会调用SpringApplication.run()
。 -
创建SpringApplication对象:
run()
方法首先创建一个SpringApplication
对象,该对象包含了应用的主要配置,如启动的类、资源和环境信息。 -
初始化启动参数:解析命令行参数,准备用于Spring Boot运行环境的参数。
-
设置初始化器(Initializers):设置并调用
ApplicationContextInitializer
,它可以在ConfigurableApplicationContext
类型的上下文完全初始化前对其进行配置或修改。 -
设置监听器(Listeners):设置并调用
ApplicationListener
,用于响应各种应用事件,包括启动过程中的一系列事件。 -
推断应用的类型:根据类路径中的存在的类(例如是否存在
ServletContext
类),推断应用是普通的Spring应用还是Web应用。 -
准备环境:准备
SpringApplication
的运行环境,包括配置默认的配置源(properties文件)、环境变量和命令行参数等。对于Web应用,还会根据不同的Web环境(Reactive, Servlet)准备不同的Web运行环境。 -
打印Banner:如果配置了Banner(在src/main/resources下的banner.txt或通过代码设置),此时输出。
-
创建应用上下文:依据推断结果,创建合适类型的Spring应用上下文(ApplicationContext),比如
AnnotationConfigServletWebServerApplicationContext
或AnnotationConfigApplicationContext
。 -
初始化应用上下文:调用之前设置的
ApplicationContextInitializer
的initialize
方法,允许用户自定义上下文的初始化。 -
应用上下文准备事件:发布
ApplicationStartedEvent
和ApplicationEnvironmentPreparedEvent
事件,允许相应地修改环境或者提前执行某些动作。 -
加载Bean定义:根据
@SpringBootApplication
(包含@ComponentScan
)和其他配置类,加载应用中的Bean定义。 -
执行自动配置:根据
spring.factories
文件中的配置,执行自动配置类,自动配置类会根据条件(@Conditional
注解)确定是否加载。 -
刷新应用上下文:刷新上下文,完成Bean的创建、依赖注入、初始化等工作。
-
执行命令行运行器:调用实现了
CommandLineRunner
和ApplicationRunner
接口Bean的run
方法。 -
应用准备完成事件:发布
ApplicationReadyEvent
,表示应用已准备好接收请求。 -
启动内嵌服务器:如果是Web应用,此时启动内嵌的Web服务器(如Tomcat、Jetty或Undertow),并初始化DispatchServlet。
-
等待应用退出:
SpringApplication.run()
结束,应用继续运行,直到收到停止命令,则进行清理并关闭上下文。
这个列表提供了Spring Boot启动过程的一个相当详尽的视角,但是实际上在实际的应用中,基于不同的配置和自定义的组件,还可能涉及更多的步骤和细节。
在Spring Boot中,ApplicationContextInitializer
和ApplicationListener
是在Spring容器的生命周期的早期阶段运行的回调接口,用于定制化容器的启动过程。由于它们运行的时间点较早,容器可能还没有完全初始化,许多Bean可能还未被创建和注册,因此在这些组件中使用@Autowired注入其他的Bean通常是不可行的或者说行为是不确定的。
对于ApplicationContextInitializer
,它直接操作ApplicationContext的配置,这发生在容器的Bean定义被加载之前,因此此时容器里面还没有Bean可以被注入。
对于ApplicationListener
,如果监听器是通过Spring的组件扫描(即带有@Component
等注解)被注册成一个Bean的话,那么它将像其他Spring管理的Bean一样,可以使用@Autowired
来注入依赖。不过,需要注意的是不所有的ApplicationListener
都会被注册为Bean,有些可以在application.properties
中通过context.listener.classes
配置,或者在META-INF/spring.factories
文件中通过org.springframework.context.ApplicationListener
配置,这些监听器不会成为容器管理的Bean,因此也就不支持@Autowired
注入。
如果您想在ApplicationListener
中注入其他Bean,并且要确保此时这些Bean已经被创建,您可能需要监听一个如ContextRefreshedEvent
的稍晚发生的事件。此时ApplicationContext已经刷新完毕,容器内的Bean已经准备就绪,可以被安全地注入。
总体来说,您应该非常小心地在ApplicationContextInitializer和ApplicationListener中注入依赖,确保这些操作在Spring容器生命周期的正确阶段内进行。如果您需要注入依赖来完成某些配置或启动任务,可能更适合使用标准的Spring Bean生命周期回调如@PostConstruct
或者实现InitializingBean
接口。对于处理特定事件,您可以考虑使用ApplicationEvent
机制并确保在合适的时间点进行依赖注入。
附:Spring Boot 内置的 Application Event
(1)Spring Boot 中包含了一些与 SpringApplication 生命周期相关的内置 Application Event,包括:
ApplicationStartingEvent:在 Spring Boot 应用程序启动之前发布。
ApplicationEnvironmentPreparedEvent:在 Spring Boot 应用程序的环境已经准备好,但正在创建 Application Context 上下文之前发布。
ApplicationContextInitializedEvent:当 Spring Boot 应用程序 Application Context 上下文准备就绪并且调用
ApplicationContextInitializers,但尚未加载 bean 定义时发布。
ApplicationPreparedEvent:在 Spring Boot 应用程序的 Application Context 上下文已经创建,但尚未刷新之前发布。
ApplicationStartedEvent:在 Spring Boot 应用程序的 Application Context 上下文已经刷新,但尚未启动之前发布。
ApplicationReadyEvent:在 Spring Boot 应用程序已经启动并准备接受请求之后发布。
ApplicationFailedEvent:在 Spring Boot 应用程序启动失败时发布。
参考:
Springboot启动流程分析(二):准备IOC容器相关信息_springboot this.preparecontext(context, environmen-CSDN博客