SpringBoot的 启动流程和自动装配 的核心原理

SpringBoot

好处

SpringBoot是基于Spring的一个脚手架项目,是对Spring的扩展。在Spring的基础上,它集成了大量主流的第三方框架,然后通过使用这些第三方的库,帮我们做了大量的自动化配置。从而达到开箱即用、简化配置的目的,使得通过很少的配置就能快速搭建起项目,将我们从繁琐的配置中解放出来,能够更加专注于业务逻辑。

启动流程

  1. 我们通过调用SpringApplication.run(主配置类.class, args)函数来启动SpringBoot,该函数执行时会去创建一个SpringApplication对象,然后调用该对象的run方法。
  2. 在创建SpringApplication对象的构造方法中,主要会去做以下几件事:
    1. 设置webApplicationType属性,默认设置为servlet。
    2. 设置初始化器集合initializers和监听器集合listeners,具体来说就是调用getSpringFactoriesInstances方法,该方法分为两步:首先,调用loadFactoryNames方法,去扫描类路径下的所有的 META-INF/spring.factories 文件,然后从中读取出某特定类型在该文件中配置的需要自动装配的类的全限定类名;其次,有了全限定类名后,通过反射来创建对应的对象。最后设置属性initializers和listeners。
    3. 分析调用栈,找到main函数,然后通过main函数得到主启动类对应的Class。
  3. 调用run方法,主要流程步骤如下:
    1. 设置id和启动时间。
    2. 调用loadFactoryNames方法从 META-INF/spring.factories 文件中读取监听器的全限定类名并反射创建对象,然后交给监听器管理者SpringApplicationRunListeners listeners管理。接下来会通过该管理者去发布一个启动事件,具体的做法是循环遍历listeners中的监听器,然后调用他们的starting方法(个人理解是通过管理者发布了一个事件,然后循环遍历监听器,如果监听器重写了starting方法就说明它监听该启动事件,故starting方法相当于监听器的回调方法),其中一个监听器的starting方法是通过事件广播器来发布事件 ApplicationStartingEvent 。通过监听该事件,就可以完成一些设置,比如说完成日志系统的初始化工作。
    3. 处理有关系统环境的信息。
    4. 打印图标Banner。
    5. 创建上下文对象context,注意此处调用的是无参构造器,并不会去调用refresh()方法
    6. 调用prepareContext方法。该方法会向context中设置系统环境信息、类型转换器;然后遍历第2步中的初始化器initializers,调用他们的initialize方法来初始化context;然后通过监听器管理者来发布context初始化完成事件ApplicationContextInitializedEvent;然后会调用load()方法将主配置类转换成 BeanDefinition 并注册到容器中;最后通过监听器管理者发布上下文加载完成事件ApplicationPreparedEvent。
    7. 调用context的refresh()函数来刷新容器。
    8. 记录结束时间,然后通过监听器管理者listeners来发布一个事件ApplicationStartedEvent,SpringBoot启动完成。

自动装配

  1. 在SpringBoot的主启动类里,除了run方法外,还有一个重要的地方就是我们加了@SpringBootApplication注解,而该注解又被@SpringBootConfiguration、@ComponentScan、@EnableAutoConfiguration标注。
  2. 在SpringBoot的启动流程中有一步是会去调用load()方法,该方法会将为主启动类创建BeanDefinition,然后将其添加到容器当中。
  3. 在SpringBoot的启动流程中还会去创建应用上下文context并且在创建过程中会向容器中加入ConfigurationClassPostProcessor的BeanBefinition,然后会去调用context的refresh()方法刷新容器,在这个过程中有一个重要的步骤是去执行所有的BeanFactoryPostProcessor,而ConfigurationClassPostProcessor就是其中的一个。
  4. ConfigurationClassPostProcessor类的作用就是去解析加了@Configuration的类,由于@SpringBootConfiguration被@Configuration标注,所以我们的主启动类会在这里进行解析。该类会去解析并处理@ComponentScan、@Bean、@Import等注解,将我们通过注解标注的Bean的定义信息加载到容器中。在这个过程中,它会去递归地搜索配置类上的注解,目的是寻找@Import注解,@EnableAutoConfiguration被@Import({AutoConfigurationImportSelector.class})标注,所以AutoConfigurationImportSelector类会被找到并被实例化(这也是所有的@Enablexxx的原理:该注解被@Import标注,然后在此处会去递归地寻找所有的@Import注解并导入它指定的类然后实例化,然后导入的该类又会向容器中注册一些组件)。
    uration被@Configuration标注,所以我们的主启动类会在这里进行解析。该类会去解析并处理@ComponentScan、@Bean、@Import等注解,将我们通过注解标注的Bean的定义信息加载到容器中。在这个过程中,它会去递归地搜索配置类上的注解,目的是寻找@Import注解,@EnableAutoConfiguration被@Import({AutoConfigurationImportSelector.class})标注,所以AutoConfigurationImportSelector类会被找到并被实例化(这也是所有的@Enablexxx的原理:该注解被@Import标注,然后在此处会去递归地寻找所有的@Import注解并导入它指定的类然后实例化,然后导入的该类又会向容器中注册一些组件)。
  5. 在找到由@Import所引入的AutoConfigurationImportSelector类后,就会去执行它的process方法,该方法会去从 META-INF/spring.factories 文件中读取由EnableAutoConfiguration所配置的要自动导入的类的全限定类名,然后再通过@ConditionalOnxxx注解来进行过滤,得到最终需要自动导入的类,并为其创建BeanDefinition然后添加到容器中。这些类都是被@Configuration标注的配置类,又会向容器中导入许多组件,从而完成自动装配的过程(通过@Enablexxx导入的类可能会是@ConditionalOnxxx注解的条件,所以加了@Enablexxx后会使得某些类不会被过滤掉,从而自动装配到容器中)。

Guess you like

Origin blog.csdn.net/zhang_qing_yun/article/details/120340515