SpringBoot系列-启动原理(上)

SpringBoot-启动原理(上)

   概要

    Spring Boot是建立在Spring框架之上的微服务框架,旨在简化Spring应用的开发过程。与传统的Spring应用相比,Spring Boot采用约定优于配置的原则,通过提供默认配置和快速开发的特性,大大减少了开发者的工作量。Spring Boot还支持快速构建独立的、可执行的JAR包,使得应用的部署变得更加简单。

   springboot的启动经过了一些一系列的处理,我们先看看整体过程的流程图:

    

   一、@SpringBootApplication 注解

   @SpringBootApplication 注解是Spring Boot的核心注解,它其实是一个组合注解。在某个类上面使用该注解,说明这个类是SpringBoot的主配置类,SpringBoot就应该运行这个类的main方法来启动SpringBoot应用。

   注解定义如下:

 1 @Target(ElementType.TYPE)
 2 @Retention(RetentionPolicy.RUNTIME)
 3 @Documented
 4 @Inherited
 5 @SpringBootConfiguration
 6 @EnableAutoConfiguration
 7 @ComponentScan(excludeFilters = {
 8         @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
 9         @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
10 public @interface SpringBootApplication {
11     //......
12 }

    1.  @SpringBootConfiguration

    允许在上下文中注册额外的 bean 或导入其他配置类

    @SpringBootConfiguration 是一个特殊的 @Configuration,用于标识 Spring Boot 的配置类。

    2. @EnableAutoConfiguration(开启自动配置)   

    @EnableAutoConfiguration 是实现自动装配的核心注解,自动装配核心功能的实现实际是通过 AutoConfigurationImportSelector类。

    @EnableAutoConfiguration 告诉 Spring Boot 根据类路径中的 jar 依赖,为项目进行自动配置。它会扫描类路径下的 META-INF/spring.factories 文件,并根据其中定义的自动配置类进行配置。

    3. @ComponentScan(开启自动扫描)

    @ComponentScan 启用组件扫描,使 Spring 能够扫描当前包及其子包中的 Spring 组件并将其注册到 Spring 容器中。

    扫描被@Component (@Service,@Controller)注解的 bean,注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描某些 bean。如下图所示,容器中将排除TypeExcludeFilter和AutoConfigurationExcludeFilter。 

    二、SpringApplication.run() 启动流程

    可以肯定的是,所有的标准的SpringBoot的应用程序都是从run方法开始的。

1 @SpringBootApplication
2 public class Application {
3 
4     public static void main(String[] args) {
5         SpringApplication.run(Application.class,args);
6     }
7

    先附上这个方法的完整代码,通过注释可以知道这个方法的作用就是创建和刷新一个新的ApplicationContext,也就是Springboot的上下文bean容器

    源码如下:

 1     public ConfigurableApplicationContext run(String... args) {
 2         // 开始执行,记录开始时间
 3         long startTime = System.nanoTime();
 4         DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
 5         ConfigurableApplicationContext context = null;
 6 
 7         // 设置系统属性 java.awt.headless 的值,默认为true
 8         this.configureHeadlessProperty();
 9 
10         // 创建所有 Spring 运行监听器
11         // 从META-INF/spring.factories中获取并启动监听器
12         // 获取SpringApplicationRunListeners,内部只有一个EventPublishingRunListener
13         SpringApplicationRunListeners listeners = this.getRunListeners(args);
14 
15         // 会封装成SpringApplicationEvent事件然后广播出去给SpringApplication中的listeners所监听
16         // 这里接受ApplicationStartedEvent事件的listener会执行相应操作
17         listeners.starting(bootstrapContext, this.mainApplicationClass);
18 
19         try {
20             // 处理 args 参数
21             // 创建ApplicationArguments 对象 初始化默认应用参数类
22             // args是启动Spring应用的命令行参数,该参数可以在Spring应用中被访问。如:--server.port=9000
23             ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
24 
25            // 准备环境
26            // 项目运行环境Environment的预配置
27            // 创建并配置当前SpringBoot应用将要使用的Environment
28            // 并遍历调用所有的SpringApplicationRunListener的environmentPrepared()方法
29             ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
30             this.configureIgnoreBeanInfo(environment);
31 
32             // 创建 Banner 的打印类
33             Banner printedBanner = this.printBanner(environment);
34 
35             // 创建Spring容器,即创建应用上下文
36             // 根据应用程序的类型,创建相应的ApplicationContext实例
37             context = this.createApplicationContext();
38             context.setApplicationStartup(this.applicationStartup);
39 
40            // 准备应用上下文
41            // Spring容器前置处理
42            // 这一步主要是在容器刷新之前的准备动作。包含一个非常关键的操作:将启动类注入容器,为后续开启自动化配置奠定基础。
43            // 把所有需要管理的 Bean 统计出来
44             this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 调用Spring的refresh方法
45 this.refreshContext(context); 46 47 48 // 应用上下文刷新之后的事件的处理 49 // 扩展接口,设计模式中的模板方法,默认为空实现。 50 // 如果有自定义需求,可以重写该方法。比如打印一些启动结束log,或者一些其它后置处理 51 this.afterRefresh(context, applicationArguments); 52 Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime); 53 if (this.logStartupInfo) { 54 (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup); 55 } 56 57 // 广播出ApplicationReadyEvent事件给相应的监听器执行 58 // 发布应用上下文启动完成事件 59 listeners.started(context, timeTakenToStartup); 60 61 // 执行所有 Runner 运行器 62 // 用于调用项目中自定义的执行器XxxRunner类,使得在项目启动完成后立即执行一些特定程序 63 // Runner 运行器用于在服务启动时进行一些业务初始化操作,这些操作只在服务启动后执行一次。 64 // Spring Boot提供了ApplicationRunner和CommandLineRunner两种服务接口 65 this.callRunners(context, applicationArguments); 66 } catch (Throwable var12) { 67 // 过程报错的话会执行一些异常操作 68 // 然后广播出ApplicationFailedEvent事件给相应的监听器执行 69 this.handleRunFailure(context, var12, listeners); 70 throw new IllegalStateException(var12); 71 } 72 73 try { 74 Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime); 75 76 // 发布应用上下文准备就绪事件 77 listeners.ready(context, timeTakenToReady); 78 79 // 返回Spring容器 80 return context; 81 } catch (Throwable var11) { 82 this.handleRunFailure(context, var11, (SpringApplicationRunListeners)null); 83 throw new IllegalStateException(var11); 84 } 85 }

 

    参考链接:

    https://www.cnblogs.com/imreW/p/17398305.html

posted @ 2024-08-03 16:41  欢乐豆123  阅读(20)  评论(0编辑  收藏  举报