• 【SpringBoot】启动过程之——SpringApplication初始化及运行


    Spring Boot 工程的主函数

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

    分为了两个部分:

    • 初始化 SpringApplication
    new SpringApplication
    
    • 1
    • 运行 SpringApplication
    springApplication.run()
    
    • 1

    1. 初始化 SpringApplication

    配置基本的环境变量、资源、构造器、监听器。

    初始化阶段的主要作用是为运行 SpringApplication 实例对象启动环境变量准备、以及进行资源构造器的初始化动作。

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
       this.resourceLoader = resourceLoader;
       Assert.notNull(primarySources, "PrimarySources must not be null");
       this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
       this.webApplicationType = WebApplicationType.deduceFromClasspath();
       this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
       setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
       setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
       this.mainApplicationClass = deduceMainApplicationClass();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    1. setInitializers,实例化所有初始器:
      加载 ApplicationContextInitializer 是在 SpringFactoriesLoader.loadFactoryNames 方法里面进行的。这个方法会尝试从类路径的 META-INF/spring.factories 读取相应配置文件,然后进行遍历,读取配置文件中Key为:org.springframework.context.ApplicationContextInitializer 的 value。
      以 spring-boot 为例,它的 Initializers 定义如下,Initializers 的作用在上一章中已详细解释
    # 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. setListeners,实例化所有监听器
      同样以 spring-boot 为例,它的 Initializers 定义如下:
    # 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2. 运行 SpringApplication

    Spring Boot 正式启动加载过程,包括启动流程监控模块、配置环境加载模块、ApplicationContext 容器上下文环境加载模块。

    其中的一些关键步骤:

    1. 发布应用启动过程中的一系列事件
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting(bootstrapContext, this.mainApplicationClass);
    
    • 1
    • 2

    SpringApplicationRunListeners 本质上是一个事件发布者,它在 SpringBoot 应用启动的不同时间点发布不同应用事件类型(ApplicationEvent):
    在这里插入图片描述
    由上文知在初始化的流程中,SpringApplication 加载了一系列 ApplicationListener,其监听的事件就是在这里发布的。

    1. 创建应用程序上下文
      ApplicationContext,也就是我们所说的 Spring Ioc 容器,是在 BeanFactory 的基础之上的一种更高级的容器,除了具有基本的 bean 管理功能之外,还提供对事件监听机制以及国际化的支持等。
    context = createApplicationContext();
    
    • 1
    1. 准备ApplicationContext
    prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
    
    • 1

    主要完成以下工作:

    • 实例化单例的 BeanNameGenerator
    // public static final String CONFIGURATION_BEAN_NAME_GENERATOR =
    //      "org.springframework.context.annotation.internalConfigurationBeanNameGenerator";
          
    context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
          this.beanNameGenerator);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Spring 定义 bean 有两种模式:配置文件(xml,properties)和注解。BeanNameGenerator 是为 bean 定义生成 bean 名称的策略接口。
    其实现类有两个:
    DefaultBeanNameGenerator :用来处理 xml 资源文件,但一般情况下在 Spring Boot 中我们很少使用 xml 来引入 bean;
    AnnotationBeanNameGenerator :处理 @Component 等注解生成 bean name。当注解中有 value 属性时,则给 bean 命名为 value 值。当没有指定名称时,则根据类名自动生成。

    • 执行初始化方法。在初始化阶段中我们加载了所有的 ApplicationContextInitializer ,依次执行
    initializer.initialize(context);
    
    • 1
    • 发布事件,通知监听者 ApplicationContext 已经准备完毕
    listeners.contextLoaded(context);
    
    void contextLoaded(ConfigurableApplicationContext context) {
       doWithListeners("spring.boot.application.context-loaded", (listener) -> listener.contextLoaded(context));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 将所有的bean加载到容器中
    // Load the sources
    Set<Object> sources = getAllSources();
    Assert.notEmpty(sources, "Sources must not be empty");
    load(context, sources.toArray(new Object[0]));
    
    • 1
    • 2
    • 3
    • 4
    • 再次发布事件,通知监听者 ApplicationContext 已经装载完毕
    listeners.contextLoaded(context);
    
    • 1
    1. 刷新上下文,属于 spring 中的机制,包括了属性自动装配等步骤
    refreshContext(context);
    
    • 1
    1. 发布上下文准备就绪事件
    listeners.started(context);
    
    • 1
  • 相关阅读:
    GBase 8c V3.0.0数据类型——模式可见性查询函数
    vs2019+Qt 使用 Qlabel 在界面上显示图像及显示失真问题
    直播分享| 腾讯云 MongoDB 智能诊断及性能优化实践
    前端知识记录
    【第2章 Node.js基础】2.2 Node.js回调函数
    Linux Command——ls
    Java 设计模式实战系列—策略模式
    有效预警6要素:亿级调用量的阿里云弹性计算SRE实践
    数据库以及数据库常用概念、ER模型相关概念
    开源大模型部署及推理所需显卡成本必读之一
  • 原文地址:https://blog.csdn.net/sun_tantan/article/details/125227236