SpringBoot源码启动流程(待完善)

目录

SpringBoot源码启动流程

1. 构造SpringApplication对象

2. run(String... args)方法

SpringApplicationRunListener.starting

创建Environment

SpringApplicationRunListeners.environmentPrepared

打印Banner

创建Spring容器

ApplicationContextInitializer初始化

SpringApplicationRunListener.contextPrepared

将启动类作为配置类注册到spring容器 

SpringApplicationRunListener.contextLoaded

刷新spring容器

SpringApplicationRunListener.started

callRunners

SpringApplicationRunListener.running

handleRunFailure处理异常

配置解析流程

SpringBoot配置优先级


SpringBoot源码启动流程

1. 构造SpringApplication对象

1.1 推测web应用类型

判断关键类是否存在来区分类型

  • REACTIVE
  • NONE
  • SERVLET
	static WebApplicationType deduceFromClasspath() {
		if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
				&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
			return WebApplicationType.REACTIVE;
		}
		for (String className : SERVLET_INDICATOR_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return WebApplicationType.NONE;
			}
		}
		return WebApplicationType.SERVLET;
	}

2. 设置Initializers和Listeners扩展点

3. 推测Main方法所在类

	public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        // 推测web应用
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
        // 设置Initializer和Listener扩展点
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		// 推测main方法所在类
        this.mainApplicationClass = deduceMainApplicationClass();
	}

2. run(String... args)方法

SpringApplicationRunListener.starting

SpringBoot提供了一个EventPublishingRunListener,它实现了SpringApplicationRunListener接口,默认情况下会利用EventPublishingRunListener发布一个ApplicationContextInitializedEvent事件,程序员可通过定义ApplicationListener来消费这个事件

		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();

创建Environment

解析配置文件, 环境变量, 启动命令参数

SpringApplicationRunListeners.environmentPrepared

用EventPublishingRunListener发布一个ApplicationEnvironmentPreparedEvent事件,默认情况会有一个EnvironmentPostProcessorApplicationListener来消费这个事件,而这个ApplicationListener接收到这个事件之后,就会解析application.properties、application.yml文件,并添加到Environment对象中去。

打印Banner

控制台打印启动springboot日志

创建Spring容器

	protected ConfigurableApplicationContext createApplicationContext() {
		Class contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				switch (this.webApplicationType) {
				case SERVLET:
					contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE:
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default:
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass",
						ex);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

ApplicationContextInitializer初始化

默认SpringBoot提供了多个ApplicationContextInitializer,其中比较重要的有ConditionEvaluationReportLoggingListener

ConditionEvaluationReportLoggingListener.initialize逻辑:

    public void initialize(ConfigurableApplicationContext applicationContext) {
        // 设置spring容器
        this.applicationContext = applicationContext;
        // 添加监听器
        applicationContext.addApplicationListener(new ConditionEvaluationReportListener());
        // 生成一个ConditionEvaluationReport对象赋值给report属性
        if (applicationContext instanceof GenericApplicationContext) {
            this.report = ConditionEvaluationReport.get(this.applicationContext.getBeanFactory());
        }
    }

ConditionEvaluationReportListener会负责接收ContextRefreshedEvent事件,也就是Spring容器一旦启动完毕就会触发ContextRefreshedEvent,ConditionEvaluationReportListener就会打印自动配置类的条件评估报告。 

SpringApplicationRunListener.contextPrepared

发布一个ApplicationContextInitializedEvent广播事件, 默认没有Listener消费

将启动类作为配置类注册到spring容器 

	private int load(Class source) {
		if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
			// Any GroovyLoaders added in beans{} DSL can contribute beans here
			GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
			load(loader);
		}
        // 注册配置类
		if (isComponent(source)) {
			this.annotatedReader.register(source);
			return 1;
		}
		return 0;
	}

SpringApplicationRunListener.contextLoaded

默认情况下会利用EventPublishingRunListener发布ApplicationPreparedEvent事件

刷新spring容器

 refreshContext会调用spring的refresh方法

SpringApplicationRunListener.started

发布ApplicationStartedEvent事件

callRunners

调用ApplicationRunner和CommandLineRunner的run方法

SpringApplicationRunListener.running

发布ApplicationReadyEvent事件

handleRunFailure处理异常

发布ApplicationFailedEvent事件

配置解析流程

  1. 添加servlet, servlet容器, 操作系统, JVM环境变量的配置
  2. 添加默认配置defaultProperties
  3. 添加命令行参数addCommandLineProperties
  4. 添加RandomValuePropertySource(ConfigFileApplicationListener消费ApplicationEnvironmentPreparedEvent事件)
  5. 添加参数-Dspring.application.json参数的配置项(ConfigFileApplicationListener消费ApplicationEnvironmentPreparedEvent事件)

SpringBoot配置优先级

官网描述:Core Features

  1. Default properties (specified by setting SpringApplication.setDefaultProperties).

  2. @PropertySource annotations on your @Configuration classes. Please note that such property sources are not added to the Environment until the application context is being refreshed. This is too late to configure certain properties such as logging.* and spring.main.* which are read before refresh begins.

  3. Config data (such as application.properties files).

  4. RandomValuePropertySource that has properties only in random.*.

  5. OS environment variables.

  6. Java System properties (System.getProperties()).

  7. JNDI attributes from java:comp/env.

  8. ServletContext init parameters.

  9. ServletConfig init parameters.

  10. Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property).

  11. Command line arguments.

  12. properties attribute on your tests. Available on @SpringBootTest and the test annotations for testing a particular slice of your application.

  13. @DynamicPropertySource annotations in your tests.

  14. @TestPropertySource annotations on your tests.

  15. Devtools global settings properties in the $HOME/.config/spring-boot directory when devtools is active.

Config data files are considered in the following order:

  1. Application properties packaged inside your jar (application.properties and YAML variants).

  2. Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants).

  3. Application properties outside of your packaged jar (application.properties and YAML variants).

  4. Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants).

你可能感兴趣的:(springboot)