Spring Boot 的启动流程是面试中常见的问题之一,理解其启动过程有助于深入掌握 Spring Boot 的工作原理。以下是 Spring Boot 启动流程的详细解析:
1. 入口点:main
方法
Spring Boot 应用程序的启动从 main
方法开始,通常使用 SpringApplication.run()
方法来启动应用。
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
@SpringBootApplication
是一个复合注解,包含以下三个核心注解:@SpringBootConfiguration
: 标识这是一个 Spring Boot 配置类。@EnableAutoConfiguration
: 开启自动配置功能。@ComponentScan
: 扫描当前包及其子包下的组件(如@Controller
,@Service
,@Repository
等)。
2. 创建 SpringApplication
实例
在调用 SpringApplication.run()
方法时,首先会创建一个 SpringApplication
对象。
public SpringApplication(Class<?>... primarySources) {
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
- 关键步骤:
- 推断应用类型:通过
WebApplicationType.deduceFromClasspath()
判断当前应用是哪种类型(NONE
,SERVLET
, 或REACTIVE
)。 - 加载初始化器:从
META-INF/spring.factories
文件中加载所有ApplicationContextInitializer
实现类。 - 加载监听器:从
META-INF/spring.factories
文件中加载所有ApplicationListener
实现类。 - 推断主类:通过堆栈信息推断出包含
main
方法的主类。
- 推断应用类型:通过
3. 调用 run
方法
SpringApplication.run()
方法是启动的核心逻辑,分为以下几个阶段:
(1) 准备环境
- 创建并配置
Environment
:- 根据应用类型(
SERVLET
或REACTIVE
),创建对应的Environment
对象(如StandardServletEnvironment
)。 - 加载外部配置(如命令行参数、系统属性、环境变量等)。
- 将
Environment
对象与SpringApplication
关联。
- 根据应用类型(
(2) 发布启动事件
- 触发
ApplicationStartingEvent
事件,通知所有监听器应用程序正在启动。
(3) 准备上下文
- 根据应用类型创建合适的
ApplicationContext
:- 如果是
SERVLET
类型,创建AnnotationConfigServletWebServerApplicationContext
。 - 如果是
REACTIVE
类型,创建AnnotationConfigReactiveWebServerApplicationContext
。 - 如果是非 Web 应用,创建
AnnotationConfigApplicationContext
。
- 如果是
- 配置上下文的初始化器和监听器。
(4) 加载 Bean 定义
- 扫描主类所在的包及其子包,加载所有的
@Component
注解类。 - 处理
@EnableAutoConfiguration
注解,加载自动配置类(如DataSourceAutoConfiguration
、WebMvcAutoConfiguration
等)。
(5) 刷新上下文
- 调用
AbstractApplicationContext.refresh()
方法,完成以下操作:- 注册 BeanFactoryPostProcessor:处理
@Configuration
和@Bean
注解。 - 注册 BeanPostProcessor:处理
@Autowired
和@Value
注解。 - 初始化单例 Bean:实例化所有非懒加载的单例 Bean。
- 启动内嵌 Web 容器(如果是 Web 应用):如 Tomcat、Jetty 或 Undertow。
- 注册 BeanFactoryPostProcessor:处理
(6) 发布完成事件
- 触发
ApplicationReadyEvent
事件,通知所有监听器应用程序已启动完成。
4. 总结启动流程
Spring Boot 的启动流程可以概括为以下几个主要步骤:
- 创建
SpringApplication
实例:推断应用类型、加载初始化器和监听器。 - 调用
run
方法:- 准备环境(
Environment
)。 - 发布启动事件(
ApplicationStartingEvent
)。 - 创建并准备
ApplicationContext
。 - 加载 Bean 定义并刷新上下文。
- 启动内嵌 Web 容器(如果需要)。
- 发布完成事件(
ApplicationReadyEvent
)。
- 准备环境(
5. 常见扩展点
在 Spring Boot 启动流程中,有一些常用的扩展点可以用来定制启动行为:
ApplicationContextInitializer
:用于在上下文刷新之前进行自定义初始化。ApplicationListener
:用于监听 Spring Boot 的生命周期事件。CommandLineRunner
和ApplicationRunner
:在应用启动完成后执行特定逻辑。
6. 面试回答建议
在面试中,可以根据问题的深度选择回答的内容:
- 如果是初级问题,只需描述从
main
方法到run
方法的基本流程。 - 如果是高级问题,可以详细说明
SpringApplication
的创建、run
方法的各个阶段以及扩展点。
例如:
Spring Boot 的启动流程从
main
方法开始,通过SpringApplication.run()
方法启动应用。首先会创建SpringApplication
实例,推断应用类型并加载初始化器和监听器。接着调用run
方法,完成环境准备、上下文创建、Bean 加载和刷新等操作。最后启动内嵌 Web 容器,并发布启动完成事件。在整个过程中,可以通过ApplicationContextInitializer
和ApplicationListener
等扩展点定制启动行为。
希望以上内容能够帮助你更好地理解和回答 Spring Boot 启动流程相关的面试题!