SpringBoot启动加载过程

文章目录

  • 1. 启动类
    • @SpringBootApplication
      • 1. @Configuration
      • 2. @EnableAutoConfiguration
      • 3. @ComponentScan
  • 2. 启动流程图
  • 3. 具体启动过程
    • 3.1 创建并构造SpringApplication对象
      • 1. 初始化资源加载器
      • 2. 初始化主要资源加载类集合并去重
      • 3. 得到当前WEB应用类型
      • 4. 设置应用上下文初始化器
      • 5. 设置监听器
      • 6. 得到主应用程序启动类
    • 3.2 调用SpringApplication对象的run方法
      • 1. 创建计时器,开始计时
      • 2. 配置系统属性(Headless)
      • 3. 初始化监听器
        • SpringApplicationRunListener监听器
      • 4. 调用监听方法starting
      • 5. 加载命令行的参数值
      • 6. 创建并配置应用环境
      • 7. 配置忽略Bean信息
      • 8. 打印Banner信息
      • 9. 创建应用上下文
        • 应用上下文对象实际类型
        • ClassPathBeanDefinitionScanner
        • AnnotatedBeanDefinitionReader
      • 10. 获取异常报告器
      • 11. 准备(配置)应用上下文
      • 12. 刷新应用上下文
      • 13. 刷新完成后的后置处理
      • 14. 停止计时
      • 15. 调用监听方法started
      • 16. 加载自定义初始化信息
      • 17. 调用监听方法running


1. 启动类

Spring Boot通常有一个名为*Application的入口类,在入口类里有一个main方法,这个main方法其实就是一个标准的java应用的入口方法。在main方法中使用SpringApplication.run方法启动SpringBoot应用项目。

@SpringBootApplication

@SpringBootApplication是Spring Boot的核心注解。它是一个组合注解,包含了一下三个注解:

  • @Configuration
  • @EnableAutoConfiguration
  • @ComponentScan

如果不使用@SpringBootApplication注解,直接使用@Configuration、@EnableAutoConfiguration、@ComponentScan也能达到相同效果。

1. @Configuration

是做类似于spring xml 工作的注解,标注在类上,类似与以前的**.xml配置文件。

2. @EnableAutoConfiguration

SpringBoot自动装配需要的注解,会让SpringBoot根据类路径中的jar包依赖为当前项目进行自动装配。同时,它也是一个组合注解,包含:

  • @Import
  • @AutoConfigurationPackage
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

其中@Import注解导入了EnableAutoConfigurationImportSelector类,这类就是自动装配关键。

自动装配是SpringBoot的一大特色。

自动配置举例:

  • 添加了spring-boot-starter-web依赖,会自动添加Tomcat和SpringMVC的依赖,SpringBoot会对Tomcat和SpringMVC进行自动配置。

  • 添加了spring-boot-starter-data-jpa依赖,SpringBoot会自动进行JPA相关的配置。

3. @ComponentScan

@ComponentScan注解用于告诉Spring哪个packages的用注解标识的类,会被spring自动扫描并且装入bean容器。

SpringBoot默认会自动扫描@SpringBootApplication所在类的同级包以及下级包的Bean(如果为JPA项目还可以扫描标注@Entity的实体类),所以建议入口类放置在最外层包下。

如果需指定扫描路径,需在启动类上加@ComponentScan注解,如下

@SpringCloudApplication
@ComponentScan(value = "com.joker")
public class CoreApplication {

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

2. 启动流程图

SpringBoot启动加载过程_第1张图片

3. 具体启动过程

springboot版本:2.2.2.RELEASE

springboot的启动过程包括:

  • 创建并构造SpringApplication对象
  • 调用SpringApplication对象的run方法

3.1 创建并构造SpringApplication对象

	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		// 初始化资源加载器,默认为null
		this.resourceLoader = resourceLoader;
		// 断言主要加载资源类不能为空
		Assert.notNull(primarySources, "PrimarySources must not be null");
		// 初始化主要资源加载类集合并去重
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		// 得到当前WEB应用类型
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		// 设置应用上下文初始化器并去重
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		// 设置监听器并去重
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		// 得到主应用程序启动类
		this.mainApplicationClass = deduceMainApplicationClass();
	}

1. 初始化资源加载器

默认为null

2. 初始化主要资源加载类集合并去重

3. 得到当前WEB应用类型

一共有三种类型:NONE、SERVLET、REACTIVE

4. 设置应用上下文初始化器

从"META-INF/spring.factories"文件读取key为ApplicationContextInitializer的实例名称集合并去重
SpringBoot启动加载过程_第2张图片SpringBoot启动加载过程_第3张图片

5. 设置监听器

从"META-INF/spring.factories"文件读取key为ApplicationListener的实例名称集合并去重(共有11个监听器)
SpringBoot启动加载过程_第4张图片

6. 得到主应用程序启动类

	private Class<?> deduceMainApplicationClass() {
		try {
			StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
			for (StackTraceElement stackTraceElement : stackTrace) {
				if ("main".equals(stackTraceElement.getMethodName())) {
					return Class.forName(stackTraceElement.getClassName());
				}
			}
		}
		catch (ClassNotFoundException ex) {
			// Swallow and continue
		}
		return null;
	}

方法调用顺序,由此找到mian方法所在类
SpringBoot启动加载过程_第5张图片

3.2 调用SpringApplication对象的run方法

run方法源码如下:

	public ConfigurableApplicationContext run(String... args) {
		// 创建计时器(任务执行观察者)
		StopWatch stopWatch = new StopWatch();
		// 开始计时
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		// 配置系统属性(Headless)
		configureHeadlessProperty();
		// 注册监听器
		SpringApplicationRunListeners listeners = getRunListeners(args);
		// 调用监听方法starting
		listeners.starting();
		try {
			// 加载命令行的参数值
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			// 创建并配置应用环境
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			// 配置忽略Bean信息
			configureIgnoreBeanInfo(environment);
			// 打印banner图形
			Banner printedBanner = printBanner(environment);
			// 创建应用上下文
			context = createApplicationContext();
			// 获取异常报告器
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			// 准备应用上下文
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
			// 刷新应用上下文
			refreshContext(context);
			// 上下文刷新完成之后的操作
			afterRefresh(context, applicationArguments);
			// 结束计时
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
			// 调用监听方法started
			listeners.started(context);
			// 执行自定义初始化
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			// 异常处理
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			// 调用监听方法running
			listeners.running(context);
		}
		catch (Throwable ex) {
			// 异常处理
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

1. 创建计时器,开始计时

创建一个StopWatch实例并执行start方法,这个类主要记录任务的执行时间

2. 配置系统属性(Headless)

配置系统属性java.awt.headless,意义不大,可以忽略。

Headless模式是在缺少显示屏、键盘或者鼠标时候的系统配置。

3. 初始化监听器

得到SpringApplicationRunListeners,内部持有:

  1. Log日志类

  2. SpringApplicationRunListener集合(里面只有一个监听器EventPublishingRunListener)

    SpringApplicationRunListener是一个接口,EventPublishingRunListener是接口的唯一实现类。
    SpringBoot启动加载过程_第6张图片

EventPublishingRunListener(事件发布运行监听器) 内部包含三个属性:

	private final SpringApplication application;

	private final String[] args;

	private final SimpleApplicationEventMulticaster initialMulticaster;

该监听器内含事件广播器SimpleApplicationEventMulticaster,主要用于广播(发布)事件。

SpringApplicationRunListener监听器

用于监听SpringApplication的run方法的执行,它有7种方法:

监听器方法 调用时间 广播的事件
starting run方法执行的时候立马调用 ApplicationStartingEvent
environmentPrepared ApplicationContext创建之前并且环境信息准备好的时候调用 ApplicationEnvironmentPreparedEvent
contextPrepared ApplicationContext创建好并且在source加载之前调用 ApplicationContextInitializedEvent
contextLoaded ApplicationContext创建并加载之后并在刷新之前调用 ApplicationPreparedEvent
started ApplicationContext已刷新且应用程序已启动,但自定义初始化信息尚未被调用时调用 ApplicationStartedEvent
running ApplicationContext已刷新并且所有自定义初始化信息都已被调用时调用 ApplicationReadyEvent
failed ApplicationContext创建过程中发生故障时调用 ApplicationFailedEvent

4. 调用监听方法starting

调用监听方法starting,广播ApplicationStartingEvent事件,触发相关的监听器(4个)

  • 获取到创建SpringApplication对象时设置的所有监听器(11个)
  • 筛选出其中监听ApplicationStartingEvent事件的那些监听器(4个),触发这些监听器
    SpringBoot启动加载过程_第7张图片

5. 加载命令行的参数值

解析在命令行中通过key=value输入的属性值,把他们封装到一个DefaultApplicationArguments类中

6. 创建并配置应用环境

创建用程序的环境Environment,并设置比如:环境信息,系统熟悉,输入参数和profile信息。

	private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// Create and configure the environment
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		ConfigurationPropertySources.attach(environment);
		listeners.environmentPrepared(environment);
		bindToSpringApplication(environment);
		if (!this.isCustomEnvironment) {
			environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
					deduceEnvironmentClass());
		}
		ConfigurationPropertySources.attach(environment);
		return environment;
	}
  • 创建环境对象
    创建环境对象,配置4个属性资源:servletConfigInitParams、servletContextInitParams、systemProperties、systemEnvironmentSpringBoot启动加载过程_第8张图片

  • 配置环境

    • 配置ConversionService(转换服务)
    • 配置PropertySources(属性资源)
    • 配置Profiles(环境),如dev、test、prod

    配置的内容包含:conversionService、activeProfiles等 SpringBoot启动加载过程_第9张图片

  • 配置附加属性资源
    配置configurationProperties
    SpringBoot启动加载过程_第10张图片

  • 调用监听方法environmentPrepared

    调用监听方法environmentPrepared,广播ApplicationEnvironmentPreparedEvent事件,触发相关的监听器(7个)
    SpringBoot启动加载过程_第11张图片

  • 绑定环境到SpringApplication中

7. 配置忽略Bean信息

SpringBoot启动加载过程_第12张图片
SpringBoot启动加载过程_第13张图片

8. 打印Banner信息

9. 创建应用上下文

也可叫创建Spring容器。根据WebApplicationType来创建应用上下文对象。在构造方法中初始化AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner。

应用上下文对象实际类型

  • SERVLET: AnnotationConfigServletWebServerApplicationContext
  • REACTIVE:AnnotationConfigReactiveWebServerApplicationContext
  • 其他:AnnotationConfigApplicationContext

ClassPathBeanDefinitionScanner

BeanDefinition扫描器,主要作用:扫描带有bean候选者相关注解的类,生成对应的BeanDefinition

bean候选者相关注解:

  • @Component
  • @Repository
  • @Service
  • @Controller

AnnotatedBeanDefinitionReader

BeanDefinition读取器,主要作用:

  • 注册内置BeanPostProcessor

  • 注册相关BeanDefinition

10. 获取异常报告器

在文件META-INF\spring.factories中获取异常报告器集合(里面只有一个报告器:FailureAnalyzers)。
在这里插入图片描述

11. 准备(配置)应用上下文

也可叫 准备(配置)Spring容器。

主要步骤如下:

  • 为应用上下文设置环境信息environment

  • 为应用上下文设置转换服务ConversionService

  • 应用上下文初始化

    执行应用上下文的初始化。一共有7个初始化器,对应用上下文进行初始化
    SpringBoot启动加载过程_第14张图片
    这些初始化器主要作用是为上下文注入BeanFactoryPostProcessor集合、ApplicationListener集合等
    在这里插入图片描述
    在这里插入图片描述

  • 调用监听方法contextPrepared

    调用监听方法contextPrepared,广播ApplicationContextInitializedEvent事件,触发相关的监听器(2个)
    在这里插入图片描述

  • 把SpringApplicationArguments、SpringBootBanner以单例形式注册到BeanFactory中

  • 加载资源配置,完成自动装配
    加载资源配置,完成自动装配。
    这里只是把资源类(这里只有@SpringBootApplication注解修饰的启动类)注册到BeanFactory中。

  • 调用监听方法contextLoaded

    调用监听方法contextLoaded,广播ApplicationPreparedEvent事件,触发相关的监听器(5个)
    SpringBoot启动加载过程_第15张图片

12. 刷新应用上下文

刷新应用上下文。在这里真正加载bean到容器中。如果是web容器,会在onRefresh方法中创建一个Server并启动。

  • 准备刷新

    prepareRefresh()

    刷新上下文环境,初始化上下文环境,对系统的环境便利或者系统属性进行准备和校验

  • 获取刷新后的bean工厂

    obtainFreshBeanFactory()

    获取新的beanFactory,销毁原有beanFactory、为每个bean生成BeanDefinition等。

    注意此处是获取新的,销毁旧的,这就是刷新的意义(Spring容器里通过BeanDefinition对象来表示Bean,BeanDefinition描述了Bean的配置信息。)

  • 准备bean工厂

    prepareBeanFactory(beanFactory)

    • 设置类加载器
    • 设置EL表达式解析器(Bean创建完成填充属性时使用)和属性注册解析器
    • 注册一些特殊的BeanPostProcessor(如:ApplicationContextAwareProcessor、ApplicationListenerDetector、)
    • 设置忽略自动装配的类(各种Aware接口的实现类)
    • 设置自动装配的类(BeanFactory,ResourceLoader,ApplicationEventPublisher,ApplicationContext)
    • 如果BeanFactory中存在loadTimeWeaver的bean,那么需要添加动态织入功能
    • 添加默认环境相关Bean(environment,systemProperties,systemEnvironment)
  • 后处理bean工厂

    postProcessBeanFactory(beanFactory)

    允许在上下文子类中对 bean 工厂进行后置处理。

    在beanfactory加载完成所有的bean后,想修改其中某个bean的定义,或者对beanFactory做一些其他的配置,就可以在子类中对beanFactory进行后置处理(子类通过实现接口BeanFactoryPostProcessor来自定义后置处理)。

    后置处理器执行的时间是:在所有的beanDenifition加载完成之后,bean实例化之前执行。

  • 调用bean工厂后置处理器

    invokeBeanFactoryPostProcessors(beanFactory)

    调用在上下文中注册为bean的工厂处理器,执行方法:

    • BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
    • BeanFactoryPostProcessor.postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
  • 注册bean后置处理器

    registerBeanPostProcessors(beanFactory)

    注册实现了BeanPostProcessor接口的bean。 SpringBoot启动加载过程_第16张图片
    例如:

    • AutowiredAnnotationBeanPostProcessor(处理被@Autowired注解修饰的bean并注入)
    • RequiredAnnotationBeanPostProcessor(处理被@Required注解修饰的方法)
    • CommonAnnotationBeanPostProcessor(处理@PreDestroy、@PostConstruct、@Resource等多个注解的作用)等。
  • 初始化消息源

    initMessageSource()

    初始化国际化工具类MessageSource。

  • 初始化应用事件广播器

    initApplicationEventMulticaster()

  • 刷新(初始化特殊的bean)

    onRefresh()

    这个方法在AbstractApplicationContext中没有实现,留给子类来初始化其他的Bean,是个模板方法,在容器刷新的时候可以自定义逻辑(子类自己去实现逻辑),不同的Spring容器做不同的事情。

    SpringBoot项目在这个阶段完成:启动内置Web容器(如Tomcat),并初始化一些特殊的bean(如DataSource)。

    这阶段主要完成的事情:

    1. 初始化主题功能
    2. 启动SpringBoot的嵌入式Tomcat服务器
      1. 启动web容器
      2. 创建ServletContext
      3. 创建Listener
      4. 创建Filter
      5. 创建Servlet
    3. 初始化一些特殊的bean
  • 注册监听器

    registerListeners()

    注册监听器,并且广播earlyApplicationEvents,也就是早期的事件

  • 完成bean工厂初始化

    finishBeanFactoryInitialization(beanFactory)

    该方法会初始化所有剩余的非懒加载单例bean,并调用BeanPostProcessors。

    除了一些内部的 bean、实现了BeanFactoryPostProcessor 接口的 bean、实现了BeanPostProcessor 接口的 bean,其他的非懒加载单例bean都会在这个方法中被初始化,BeanPostProcessor的触发也是在这个方法中。

  • 完成刷新

    finishRefresh()

    通知生命周期处理器LifecycleProcessor完成刷新过程,同时发出ContextRefreshEvent通知别人

    refresh做完之后需要做的其他事情:

    • 清除上下文资源缓存(如扫描中的ASM元数据)
    • 初始化上下文的生命周期处理器,并刷新(找出Spring容器中实现了Lifecycle接口的bean并执行start()方法)。
    • 发布ContextRefreshedEvent事件告知对应的ApplicationListener进行响应的操作

13. 刷新完成后的后置处理

上下文刷新完成之后的操作,调用afterRefresh方法。默认什么都不做,主要方便扩展。

14. 停止计时

15. 调用监听方法started

广播ApplicationStartedEvent事件。Spring启动结束,开始所有的监听器对象

16. 加载自定义初始化信息

加载自定义初始化信息,用于扩展,相当于开机启动。

此时会获取到ApplicationRunner、CommandLineRunner这两个接口类型的所有bean集合,循环调用每一个bean的run方法。

17. 调用监听方法running

广播ApplicationReadyEvent事件。应用启动完成,可以对外提供服务了。

你可能感兴趣的:(SpringBoot,spring,boot)