SpringApplication构造方法
SpringBoot作为Spring框架的一个子项目,以其简洁的配置和快速的开发部署能力,迅速成为Java领域最受欢迎的微服务框架之一。理解SpringBoot的启动流程,特别是SpringApplication的构造方法,对于深入掌握SpringBoot框架至关重要。本文将详细解析SpringBoot的启动流程,特别是SpringApplication的构造方法。
一、SpringBoot启动流程概述
SpringBoot的启动流程大致可以分为以下几个步骤:
-
SpringApplication的实例化:通过调用
SpringApplication.run()
方法,首先会创建一个SpringApplication的实例。 - 推断应用类型:根据类路径下的相关类,推断出当前应用是Web应用(包括Servlet和Reactive两种类型)还是非Web应用。
-
加载初始化器和监听器:从
spring.factories
文件中读取并实例化所有的ApplicationContextInitializer和ApplicationListener。 -
推断启动类:推断出包含
main
方法的启动类。 - 准备环境:创建并初始化ConfigurableEnvironment,包括加载配置文件、绑定属性等。
- 创建ApplicationContext:根据应用类型创建相应的ApplicationContext(如AnnotationConfigApplicationContext或AnnotationConfigServletWebServerApplicationContext)。
-
刷新上下文:调用ApplicationContext的
refresh()
方法,实例化所有的Bean,完成依赖注入等。 -
执行自定义的run方法:执行通过
@SpringBootApplication
中的@RunWith
或@SpringBootTest
指定的自定义run方法(如果有的话)。 - 发布就绪事件:发布ApplicationReadyEvent事件,标志着SpringBoot应用已经启动并可以处理请求。
二、SpringApplication构造方法详解
SpringApplication的构造方法是SpringBoot启动流程中的第一步,它负责初始化SpringApplication实例,并准备后续启动流程所需的各种资源。
1. SpringApplication构造方法签名
SpringApplication类提供了多个构造方法,其中最常用的是以下两个:
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 后续初始化步骤
}
其中,primarySources
参数是包含main
方法的启动类及其相关配置类。resourceLoader
参数是一个可选的资源加载器,用于加载配置文件等资源。
2. 推断应用类型
在SpringApplication的构造方法中,首先会根据类路径下的相关类来推断出当前应用是Web应用还是非Web应用。这一步骤是通过调用WebApplicationType.deduceFromClasspath()
方法实现的。
this.webApplicationType = WebApplicationType.deduceFromClasspath();
WebApplicationType
是一个枚举类,包含三种类型:NONE
(非Web应用)、SERVLET
(基于Servlet的Web应用)和REACTIVE
(响应式Web应用)。推断应用类型的逻辑主要依赖于检查类路径下是否存在特定的类。例如,如果存在org.springframework.web.reactive.DispatcherHandler
类且不存在org.springframework.web.servlet.DispatcherServlet
类,则应用类型为REACTIVE
;如果存在org.springframework.web.servlet.DispatcherServlet
类,则应用类型为SERVLET
;否则,应用类型为NONE
。
3. 加载初始化器和监听器
接下来,SpringApplication会从spring.factories
文件中读取并实例化所有的ApplicationContextInitializer和ApplicationListener。这些初始化器和监听器会在后续的应用上下文创建和刷新过程中被调用。
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
spring.factories
文件通常位于META-INF
目录下,是SpringBoot用于自动配置的一个重要文件。它包含了各种自动配置类的全限定名,以及与之关联的初始化器和监听器。getSpringFactoriesInstances
方法会读取这个文件,并实例化指定的类。
4. 推断启动类
在构造方法的最后一步,SpringApplication会推断出包含main
方法的启动类。这一步骤是通过调用deduceMainApplicationClass()
方法实现的。该方法会遍历primarySources
参数中的类,找到包含main
方法的类,并将其设置为启动类。
this.mainApplicationClass = deduceMainApplicationClass();
推断启动类的目的是为了在后续的应用上下文创建和刷新过程中,能够正确地加载和注册启动类中的Bean。
三、SpringApplication构造方法后的流程
虽然本文的重点是解析SpringApplication的构造方法,但了解构造方法后的流程对于全面理解SpringBoot的启动流程也是必要的。
在构造方法完成后,会调用SpringApplication.run()
方法来启动应用。run
方法会执行一系列的操作,包括:
- 构造一个StopWatch计时器,用于记录SpringBoot的启动时间。
- 初始化监听器,并发布ApplicationStartingEvent事件。
- 准备环境变量,包括加载配置文件、绑定属性等。
- 打印banner和版本信息。
- 创建ApplicationContext上下文,并填充环境变量和设置的参数。
- 调用初始化的切面,发布ApplicationContextInitializedEvent事件。
- 刷新上下文,实例化所有的Bean,完成依赖注入等。
- 发布上下文准备就绪事件(ContextRefreshedEvent),并执行自定义的run方法(如果有的话)。
- 最后,发布SpringBoot程序已启动事件(ApplicationStartedEvent),并调用ApplicationRunner和CommandLineRunner(如果有的话)。
- 发布就绪事件(ApplicationReadyEvent),标志着SpringBoot应用已经启动并可以处理请求。
四、总结
SpringBoot的启动流程是一个复杂而有序的过程,其中SpringApplication的构造方法是启动流程的第一步,也是后续步骤的基础。通过详细解析SpringApplication的构造方法,我们可以了解到SpringBoot是如何推断应用类型、加载初始化器和监听器以及推断启动类的。同时,了解构造方法后的流程也有助于我们全面理解SpringBoot的启动过程。
SpringBoot的启动流程不仅展示了其强大的自动配置能力,也体现了其灵活性和可扩展性。通过自定义初始化器、监听器和Bean等,我们可以轻松地扩展和定制SpringBoot应用,以满足不同的业务需求。希望本文能够帮助读者深入理解SpringBoot的启动流程,为后续的SpringBoot开发打下坚实的基础。