SpringBoot启动的时候做了什么(1)

大家都知道SpringBoot是靠一个main()方法启动的,那么这个main()背后做了什么呢?
//本来是想找点八股文看看的,看到网上文章要么版本太低,要么还得关注公众号,要么太深入细节。太深入咱也看不懂啊,那咋整,自己扒拉代码自己看呗

sb版本:2.7.x
我直接从github上fork的源码来看的,如需自取:https://github.com/spring-projects/spring-boot
代码拉下来之后,项目结构是这样的
在这里插入图片描述
咱也不管啥结构了,直接找代码:SpringApplication
直接看run方法

//这里的primarySources就是我们的应用程序的主类,这里的args就是我们的应用程序的参数
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
	//这里可以看到SpringApplication的启动有两部分组成
	//1:实例化SpringApplication对象·
	//2:调用SpringApplication.run()方法进行启动
	return new SpringApplication(primarySources).run(args);
}

其实就是做了两步:

  1. 实例化SpringApplication对象
  2. run(args)

SpringApplication对象的实例化

new SpringApplication(primarySources)

创建对象的时候传了一个参数,这个primarySources其实就是从main()方法传过来的。
我们的main是这样的:

public static void main(String[] args) {
  	SpringApplication.run(DubboNacosProviderApplication.class, args);
}

run的第一个参数其实就是primarySources
接着SpringApplication的构造函数

public SpringApplication(Class<?>... primarySources) {
	this(null, primarySources);
}

继续点这个this

@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
	this.resourceLoader = resourceLoader;
	Assert.notNull(primarySources, "PrimarySources must not be null");

	//将项目启动类(primarySources)存起来,用于启动项目时,获取项目启动类的类名
	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));

	//获取下当前项目的类型,有三种类型:NONE、SERVLET、REACTIVE(spring5之后出现webflux交互式的框架)
	this.webApplicationType = WebApplicationType.deduceFromClasspath();

	//这是干嘛的?
	this.bootstrapRegistryInitializers = new ArrayList<>(
			getSpringFactoriesInstances(BootstrapRegistryInitializer.class));

	//设置初始化器(Initializer),最后会去调用这些初始化器的init方法
	//spring-boot-autoconfigure的spring.factories文件中的初始化器
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

	//设置启动“main”的类,这个类是项目的主类,也就是项目的入口类
	this.mainApplicationClass = deduceMainApplicationClass();
}

其实就是主要做了以下几件事:

  1. 根据传进来的primarySources把入口类地址存一下,留着后边用。
  2. 判断下当前项目的类型,是mvc还是webflux。this.webApplicationType = WebApplicationType.deduceFromClasspath()这个方法就是根据当前classpath下是否有指定class去判断的,逻辑很简单。
  3. 设定初始化器和监听器

关于这个代码中的BootstrapRegistryInitializer ,是个接口,当前版本的spring.factories中也没找到相关默认实现,那肯定就是留给开发者自己去玩的,咱先不管是干啥的,接着往后边看。

ApplicationContextInitializer

# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
this.initializers = new ArrayList<>(initializers);

ApplicationListener

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.env.EnvironmentPostProcessorApplicationListener
this.= new ArrayList<>(listeners);

以上initializers listeners 后边用到的时候再讲

下一篇继续写run(args)的逻辑

Spring Boot 应用的启动过程是一个高度封装但又极其清晰的流程,它通过自动配置和约定优于配置的理念,极大简化了 Spring 应用的开发和部署。以下是其启动过程的详细解析: ### 1. 启动入口:`main` 方法 Spring Boot 应用的启动入口是一个标准的 Java `main` 方法,通常如下所示: ```java public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } ``` 该方法调用了 `SpringApplication.run()` 方法,传入主配置类和命令行参数。这一步是整个启动流程的起点。 ### 2. 创建 `SpringApplication` 实例 在 `run()` 方法内部,首先会创建一个 `SpringApplication` 实例。这个实例的构造函数会完成以下关键操作: - 推断应用类型(如是否为 Web 应用)。 - 加载所有 `ApplicationContextInitializer` 和 `ApplicationListener`。 - 确定主配置类(即标注 `@SpringBootApplication` 的类)。 这个过程会根据类路径中的依赖(如是否存在 `Servlet` 或 `Tomcat` 相关类)来决定使用哪种 `ApplicationContext`,例如 `AnnotationConfigServletWebServerApplicationContext` 用于 Web 应用[^1]。 ### 3. 运行 `SpringApplication.run()` 方法 调用 `run()` 方法后,Spring Boot 会执行以下核心步骤: #### a. 初始化 `ConfigurableApplicationContext` 根据应用类型创建对应的 `ApplicationContext`,例如 Web 应用会创建 `ServletWebServerApplicationContext`。 #### b. 准备环境(Environment) 在上下文刷新之前,会准备 `Environment` 对象,加载系统环境变量、JVM 参数以及配置文件(如 `application.properties` 或 `application.yml`)。 #### c. 应用初始化器(`ApplicationContextInitializer`) 这些是预先注册的初始化器,会在上下文刷新前被调用,用于对上下文进行定制化配置。 #### d. 监听器(`ApplicationListener`) 监听应用生命周期事件,例如 `ApplicationStartingEvent`、`ApplicationReadyEvent` 等。 #### e. 刷新上下文(`refreshContext()`) 这是整个启动流程的核心部分,调用了 Spring 框架的 `AbstractApplicationContext.refresh()` 方法,完成以下关键任务: - 加载 Bean 定义(Bean Definitions)。 - 实例化 Bean。 - 自动装配(`@Autowired`)。 - 初始化 Bean(如 `InitializingBean` 回调)。 - 注册 `BeanPostProcessor` 和 `BeanFactoryPostProcessor`。 在此过程中,Spring Boot 的自动配置机制也在此阶段生效。 ### 4. 自动配置原理 Spring Boot 的自动配置依赖于 `@EnableAutoConfiguration` 注解,该注解通常被包含在 `@SpringBootApplication` 注解中。 #### a. `@EnableAutoConfiguration` 的作用 该注解会触发自动配置机制,Spring Boot 会根据类路径中的依赖,自动加载合适的配置类。例如: - 如果检测到 `spring-boot-starter-web`,则会自动配置内嵌的 Tomcat 和 Spring MVC。 - 如果检测到 `spring-boot-starter-data-jpa`,则会自动配置数据源和 JPA 相关组件。 #### b. 自动配置类的加载 Spring Boot 通过 `spring.factories` 文件来加载自动配置类。该文件位于 `META-INF/spring.factories`,其中定义了所有候选的自动配置类。例如: ```properties org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.data.jpa.JpaAutoConfiguration ``` 这些配置类会根据 `@ConditionalOnClass`、`@ConditionalOnMissingBean` 等条件注解判断是否生效。 #### c. 条件化配置 自动配置类中广泛使用了条件注解,例如: - `@ConditionalOnClass`:只有在类路径存在指定类时才生效。 - `@ConditionalOnMissingBean`:只有在容器中没有定义某个 Bean 时才创建。 - `@ConditionalOnProperty`:根据配置文件中的属性决定是否启用配置。 这些条件注解确保了自动配置的灵活性和安全性。 ### 5. 启动内嵌服务器(Web 应用场景) 对于 Web 应用,Spring Boot启动内嵌的 Web 服务器(如 Tomcat、Jetty 或 Undertow)。这一过程发生在 `refreshContext()` 中的 `onRefresh()` 方法中,具体逻辑由 `ServletWebServerApplicationContext` 实现。 内嵌服务器的启动流程包括: - 创建 Web 服务器实例。 - 注册 `Servlet`、`Filter` 和 `ServletContextListener`。 - 启动服务器并监听指定端口。 ### 6. 应用启动完成事件 当上下文完全刷新后,Spring Boot 会发布 `ApplicationReadyEvent` 事件,表示应用已准备好接收请求。开发者可以通过监听该事件执行一些初始化逻辑。 --- ###
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高级摸鱼工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值