Spring Boot的运行流程

一般在Spring Boot应用的主方法中,都会调用SpringApplication类中的run方法来启动框架。而该方法则是Spring Boot的运行流程这条主线的入口,本文将会以此方法为起点,来完整分析Spring Boot的运行流程。


本文分析的Spring Boot源码版本是2.7.x,Spring Framework的源码版本是5.3.22。本文涉及的源码中存在大量与Spring Framework交互的情况,为了提高阅读体验,这里仅仅展示Spring Boot相关的源码,尽量不过多涉及Spring Framework源码。

run方法

SpringApplication中共有3个run方法,其中一个实例方法,两个静态方法。在静态的run方法中,也是先创建SpringApplication对象(参考Spring Boot的构造流程),然后调用实例run方法。

静态run方法

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    return run(new Class<?>[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    return new SpringApplication(primarySources).run(args);
}

真正的重点在实例run方法中。

实例run方法

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
private boolean logStartupInfo = true;
private ApplicationStartup applicationStartup = ApplicationStartup.DEFAULT;
/**
 * Run the Spring application, creating and refreshing a new
 * {@link ApplicationContext}.
 * @param args the application arguments (usually passed from a Java main method)
 * @return a running {@link ApplicationContext}
 */
public ConfigurableApplicationContext run(String... args) {
    long startTime = System.nanoTime();
    // 创建启动上下文
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    // 该变量记录Spring中的应用上下文
    ConfigurableApplicationContext context = null;
    // 配置headless属性
    configureHeadlessProperty();
    // 获取SpringApplicationRunLister数组并封装成SpringApplicationRunListeners
    SpringApplicationRunListeners listeners = getRunListeners(args);
    /*
     * 启动listener,内部会遍历各个SpringApplicationRunLister,
     * 对于默认的EventPublishingRunListener而言,内部会通过事件广播器向各个ApplicationListener广播starting事件。
     */
    listeners.starting(bootstrapContext, this.mainApplicationClass);

    /*
     * 这里简要对事件处理做一个总结(以starting事件为例,其他类型事件相似):
     * SpringApplicationRunListeners.starting ->
     * 遍历SpringApplicationRunListener,依次调用每个listener的starting方法 ->
     * EventPublishingRunListener.starting ->
     * initialMulticaster.multicastEvent(ApplicationStartingEvent) 或者 context.publishEvent
     *
     * EventPublishingRunListener内部针对不同的事件处理的方式有区别,有些是通过initialMulticaster.multicastEvent处理的,
     * 另外有些是通过context.publishEvent来处理的,这是为什么?
     * contextLoad事件是不同事件广播方式的分水岭,因为该事件发生时,context才算初始化完成,之后才能利用context.publishEvent来发布事件。
     *
     */

    try {
        // 创建应用参数对象
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        // 加载属性配置
        ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
        // 配置spring.beaninfo.ignore属性
        configureIgnoreBeanInfo(environment);
        // 打印banner (此功能华而不实,跳过)
        Banner printedBanner = printBanner(environment);
        // 创建应用上下文
        context = createApplicationContext();
        // 设置应用上下文的startup,应用上下文本身的启动也有很多阶段,所以可以用该startup来记录
        context.setApplicationStartup(this.applicationStartup);
        // 准备应用上下文和属性对象之间的关联
        prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
        // 初始化(刷新)应用上下文, 这里最终调用的是特别熟悉且重要和复杂的AbstractApplicationContext#refresh()方法
        refreshContext(context);
        // 执行应用上下文刷新之后的操作,默认是空操作
        afterRefresh(context, applicationArguments);
        // 计算启动耗时
        Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
        // 打印启动耗时到日志中
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
        }
        // 通知listener,应用上下文启动完毕
        listeners.started(context, timeTakenToStartup);
        // 调用runner
        callRunners(context, applicationArguments);
    }
    catch (Throwable ex) {
        // 处理异常
        handleRunFailure(context, ex, listeners);
        throw new IllegalStateException(ex);
    }
    try {
        // 计算应用上下文准备时间
        Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
        // 通知listener,应用上下文准备完毕
        listeners.ready(context, timeTakenToReady);
    }
    catch (Throwable ex) {
        // 异常处理
        handleRunFailure(context, ex, null);
        throw new IllegalStateException(ex);
    }
    // 返回应用上下文对象
    return context;
}

这个方法的涉及的内容稍微有点多,大致可以总结为下面的流程:

  • 创建启动上下文;
  • 配置headless属性;
  • 获取SpringApplicationRunListener
  • 发起starting事件;
  • 准备environment;
    • 发起environmentPrepared事件;
  • 创建应用上下文;
  • 刷新应用上下文;
  • 发起started事件;
  • 调用runner;

下面依次对上面几个步骤进行展开分析。

启动上下文

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
private DefaultBootstrapContext createBootstrapContext() {
    // 直接创建默认启动上下文实例
    DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
    // 通过构造流程中创建的初始化器对上下文实例进行初始化,默认情况下bootstrapRegistryInitializers列表的长度为0
    this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
    return bootstrapContext;
}

在Spring Boot的默认情况下,没有自动配置BootstrapRegistryInitializer,但在Spring Cloud中会使用,具体细节在相应文章中进行分析。

headless属性

在Linux服务器使用Spring Boot进行图形化操作的时候,会遇到性能问题。原因在于Java图形化工具包AWT在某些情况下会使用图形化界面操作,而Linux服务器一般没有图形化支持,因此会导致处理速度非常慢。 所以可以通过设置系统参数java.awt.headlesstrue来禁用AWT的图形界面。

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";
private boolean headless = true;
private void configureHeadlessProperty() {
    // 这里其实是在设置`java.awt.headless`属性的默认值, this.headless默认值是true。
    System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
            System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}

SpringApplicationRunListener

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
private ApplicationStartup applicationStartup = ApplicationStartup.DEFAULT;
	private SpringApplicationRunListeners getRunListeners(String[] args) {
		// 实例化SpringApplicationRunListener子类的时查找对应构造器的参数类型
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		/*
		 * 从spring.factories文件中加载SpringApplicationRunListener相关配置,并实例化这些配置类的对象,
		 * 然后作为参数(第二个参数)构造SpringApplicationRunListeners
		 * 默认仅提供了一个,即EventPublishingRunListener, 参考文件spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories
		 */
		return new SpringApplicationRunListeners(logger,
				getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
				this.applicationStartup);
	}

Spring Boot会从spring.factories文件中加载SpringApplicationRunListener配置的类型并实例化,默认情况下就只配置了一个:EventPublishingRunListener。然后将其封装为SpringApplicationRunListenersApplicationStartup用于标记应用启动的阶段,在这里使用到了ApplicationStartup.DEFAULT,默认的是空实现,即其实现的StartupStep不做什么操作。

ApplicationStartup
DefaultApplicationStartup
<
>
java
spring-core/src/main/java/org/springframework/core/metrics/ApplicationStartup.java
/**
 * Instruments the application startup phase using {@link StartupStep steps}.
 * <p>The core container and its infrastructure components can use the {@code ApplicationStartup}
 * to mark steps during the application startup and collect data about the execution context
 * or their processing time.
 *
 * @author Brian Clozel
 * @since 5.3
 */
public interface ApplicationStartup {

	/**
	 * Default "no op" {@code ApplicationStartup} implementation.
	 * <p>This variant is designed for minimal overhead and does not record data.
	 */
	ApplicationStartup DEFAULT = new DefaultApplicationStartup();

	/**
	 * Create a new step and marks its beginning.
	 * <p>A step name describes the current action or phase. This technical
	 * name should be "." namespaced and can be reused to describe other instances of
	 * the same step during application startup.
	 * @param name the step name
	 */
	StartupStep start(String name);

}
java
spring-core/src/main/java/org/springframework/core/metrics/DefaultApplicationStartup.java
/**
 * Default "no op" {@code ApplicationStartup} implementation.
 *
 * <p>This variant is designed for minimal overhead and does not record events.
 *
 * @author Brian Clozel
 */
class DefaultApplicationStartup implements ApplicationStartup {

	private static final DefaultStartupStep DEFAULT_STARTUP_STEP = new DefaultStartupStep();

	@Override
	public DefaultStartupStep start(String name) {
		return DEFAULT_STARTUP_STEP;
	}


	static class DefaultStartupStep implements StartupStep {

		private final DefaultTags TAGS = new DefaultTags();

		@Override
		public String getName() {
			return "default";
		}

		@Override
		public long getId() {
			return 0L;
		}

		@Override
		public Long getParentId() {
			return null;
		}

		@Override
		public Tags getTags() {
			return this.TAGS;
		}

		@Override
		public StartupStep tag(String key, String value) {
			return this;
		}

		@Override
		public StartupStep tag(String key, Supplier<String> value) {
			return this;
		}

		@Override
		public void end() {

		}


		static class DefaultTags implements StartupStep.Tags {

			@Override
			public Iterator<StartupStep.Tag> iterator() {
				return Collections.emptyIterator();
			}
		}
	}

}

SpringApplicationRunListeners

SpringApplicationRunListeners中定义了很多事件方法,可以通过这些方法来发起事件。这些方法都是在遍历所封装的SpringApplicationRunListener,然后通过listener来执行操作。

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplicationRunListeners.java
class SpringApplicationRunListeners {

	private final Log log;

	private final List<SpringApplicationRunListener> listeners;

	private final ApplicationStartup applicationStartup;

	SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners,
			ApplicationStartup applicationStartup) {
		this.log = log;
		this.listeners = new ArrayList<>(listeners);
		this.applicationStartup = applicationStartup;
	}

	void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
		// 调用每一个listener的starting方法
		doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
				(step) -> {
					if (mainApplicationClass != null) {
						step.tag("mainApplicationClass", mainApplicationClass.getName());
					}
				});
	}

	void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
		doWithListeners("spring.boot.application.environment-prepared",
				(listener) -> listener.environmentPrepared(bootstrapContext, environment));
	}

	void contextPrepared(ConfigurableApplicationContext context) {
		doWithListeners("spring.boot.application.context-prepared", (listener) -> listener.contextPrepared(context));
	}

	void contextLoaded(ConfigurableApplicationContext context) {
		doWithListeners("spring.boot.application.context-loaded", (listener) -> listener.contextLoaded(context));
	}

	void started(ConfigurableApplicationContext context, Duration timeTaken) {
		doWithListeners("spring.boot.application.started", (listener) -> listener.started(context, timeTaken));
	}

	void ready(ConfigurableApplicationContext context, Duration timeTaken) {
		doWithListeners("spring.boot.application.ready", (listener) -> listener.ready(context, timeTaken));
	}

	void failed(ConfigurableApplicationContext context, Throwable exception) {
		doWithListeners("spring.boot.application.failed",
				(listener) -> callFailedListener(listener, context, exception), (step) -> {
					step.tag("exception", exception.getClass().toString());
					step.tag("message", exception.getMessage());
				});
	}

	private void callFailedListener(SpringApplicationRunListener listener, ConfigurableApplicationContext context,
			Throwable exception) {
		try {
			listener.failed(context, exception);
		}
		catch (Throwable ex) {
			if (exception == null) {
				ReflectionUtils.rethrowRuntimeException(ex);
			}
			if (this.log.isDebugEnabled()) {
				this.log.error("Error handling failed", ex);
			}
			else {
				String message = ex.getMessage();
				message = (message != null) ? message : "no error message";
				this.log.warn("Error handling failed (" + message + ")");
			}
		}
	}

	private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction) {
		doWithListeners(stepName, listenerAction, null);
	}

	private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
			Consumer<StartupStep> stepAction) {
		/*
		 * 创建表示启动步骤的对象
		 * 这里的this.applicationStartup默认情况下是DefaultApplicationStartup,start后创建的是DefaultStartupStep对象,
		 * 而DefaultStartupStep的tag和end都是空操作,即什么都不做。
		 */
		StartupStep step = this.applicationStartup.start(stepName);
		// 执行listener操作
		this.listeners.forEach(listenerAction);
		// 执行step操作
		if (stepAction != null) {
			stepAction.accept(step);
		}
		// 结束当前启动步骤
		step.end();
	}

}

EventPublishingRunListener

在其构造方法中,创建了事件广播器,并往里面添加了事件监听器。这里的事件监听器就是在SpringApplication构造过程中创建的。

v2.7.x
EventPublishingRunListener
ApplicationListener配置
<
>
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/event/EventPublishingRunListener.java
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {

	private final SpringApplication application;

	private final String[] args;

	private final SimpleApplicationEventMulticaster initialMulticaster;

	public EventPublishingRunListener(SpringApplication application, String[] args) {
		this.application = application;
		this.args = args;
		// 创建事件广播器
		this.initialMulticaster = new SimpleApplicationEventMulticaster();
		/*
		 * 这里的ApplicationListener是在构建SpringApplication的时候根据spring.factories中的配置来创建的;
		 * 而EventPublishingRunListener(作为SpringApplicationRunListener的子类)则是在SpringApplication的run方法执行的时候根据
		 * spring.factories中的配置来创建的,别搞混了这两种listener
		 */
		for (ApplicationListener<?> listener : application.getListeners()) {
			// 往事件广播器中注册事件监听器,便于后续将事件发送到事件监听器
			this.initialMulticaster.addApplicationListener(listener);
		}
	}

	@Override
	public int getOrder() {
		return 0;
	}

	@Override
	public void starting(ConfigurableBootstrapContext bootstrapContext) {
		// 广播starting事件
		this.initialMulticaster
				.multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
	}

	@Override
	public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
			ConfigurableEnvironment environment) {
		// 广播environmentPrepared事件
		this.initialMulticaster.multicastEvent(
				new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment));
	}

	@Override
	public void contextPrepared(ConfigurableApplicationContext context) {
		// 广播applicationContextInitialized事件
		this.initialMulticaster
				.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
	}

	@Override
	public void contextLoaded(ConfigurableApplicationContext context) {
		for (ApplicationListener<?> listener : this.application.getListeners()) {
			if (listener instanceof ApplicationContextAware) {
				((ApplicationContextAware) listener).setApplicationContext(context);
			}
			context.addApplicationListener(listener);
		}
		// 广播applicationPrepared事件
		this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
	}

	@Override
	public void started(ConfigurableApplicationContext context, Duration timeTaken) {
		context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context, timeTaken));
		// 发布applicationStarted事件
		AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
	}

	@Override
	public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
		context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context, timeTaken));
		// 发布applicationReady事件
		AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
	}

	@Override
	public void failed(ConfigurableApplicationContext context, Throwable exception) {
		ApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception);
		if (context != null && context.isActive()) {
			// Listeners have been registered to the application context so we should
			// use it at this point if we can
			context.publishEvent(event);
		}
		else {
			// An inactive context may not have a multicaster so we use our multicaster to
			// call all of the context's listeners instead
			if (context instanceof AbstractApplicationContext) {
				for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
						.getApplicationListeners()) {
					this.initialMulticaster.addApplicationListener(listener);
				}
			}
			this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
			this.initialMulticaster.multicastEvent(event);
		}
	}

	private static class LoggingErrorHandler implements ErrorHandler {

		private static final Log logger = LogFactory.getLog(EventPublishingRunListener.class);

		@Override
		public void handleError(Throwable throwable) {
			logger.warn("Error calling ApplicationEventListener", throwable);
		}

	}

}
properties
spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories
# 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

在这些事件方法中,都是先创建事件对象ApplicationEvent,然后交由SimpleApplicationEventMulticaster进行广播。 SimpleApplicationEventMulticaster是Spring Framework提供的类,内部实现很简单,就是调用各个ApplicationListeneronApplicationEvent方法,这里就不贴代码了。

Environment

prepareEnvironment方法中处理Spring Boot应用的Environment对象。

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
private boolean isCustomEnvironment = false;
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
        DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
    // Create and configure the environment
    // 获取或创建environment
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    // 注意,这里调用的getSourceArgs()并不是返回内部的source属性(已解析参数),而是args(未解析参数)
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    // 如果environment中不存在名为configurationProperties的属性源,则创建新的对象并将其放在属性源列表中的第一个
    ConfigurationPropertySources.attach(environment);
    // 广播environmentPrepared事件
    listeners.environmentPrepared(bootstrapContext, environment);
    // 将默认属性源移动到列表末尾
    DefaultPropertiesPropertySource.moveToEnd(environment);
    // 确保environment中不包含environment-prefix属性
    Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
            "Environment prefix cannot be set via properties.");
    // 绑定environment和当前SpringApplication实例的关系
    bindToSpringApplication(environment);
    // 是否需要自定义environment,默认是false
    if (!this.isCustomEnvironment) {
        // 创建environmentConverter对象
        EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
        /*
         * 将environment对象转换为目标类型的实例,deduceEnvironmentClass()主要是区分Servlet和Reactive。
         * 因为是可以直接为SpringApplication实例设置environment属性的,所以这里是在确保设置的Environment类型和应用类型是一致的,
         * 如果不一致,会自动进行转换。
         */
        environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
    }
    // 这里为什么要再次attach?是为了确保configurationPropertySource位于列表中的第一个位置?
    ConfigurationPropertySources.attach(environment);
    return environment;
}

整个方法可以总结为下面的几个步骤:

  • 获取或创建environment对象;
  • 处理命令行参数;
  • 处理配置属性源 ConfigurationPropertySources
  • 广播environmentPrepared事件;
  • 处理默认属性源DefaultPropertiesPropertySource
  • 绑定environment和SpringApplication的关系;
  • 自定义environment;

getOrCreateEnvironment方法

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
private ConfigurableEnvironment getOrCreateEnvironment() {
    // 如果已存在,则直接返回
    if (this.environment != null) {
        return this.environment;
    }
    /*
     * 如果不存在,则根据web应用类型创建不同类型的environment
     * 对于ApplicationServletEnvironment和ApplicationReactiveWebEnvironment,两者的实现一样,
     * 为什么不在这两者的基础上再抽象一层?
     */
    switch (this.webApplicationType) {
    case SERVLET:
        return new ApplicationServletEnvironment();
    case REACTIVE:
        return new ApplicationReactiveWebEnvironment();
    default:
        return new ApplicationEnvironment();
    }
}

这里利用到了SpringApplication构造阶段探测的web应用类型,对于不同类型的应用,创建不同的Environment对象。

v2.7.x
ApplicationServletEnvironment
ApplicationReactiveWebEnvironment
<
>
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ApplicationServletEnvironment.java
class ApplicationServletEnvironment extends StandardServletEnvironment {

	@Override
	protected String doGetActiveProfilesProperty() {
		return null;
	}

	@Override
	protected String doGetDefaultProfilesProperty() {
		return null;
	}

	@Override
	protected ConfigurablePropertyResolver createPropertyResolver(MutablePropertySources propertySources) {
		// 创建属性解析器
		return ConfigurationPropertySources.createPropertyResolver(propertySources);
	}

}
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ApplicationReactiveWebEnvironment.java
class ApplicationReactiveWebEnvironment extends StandardReactiveWebEnvironment {

	@Override
	protected String doGetActiveProfilesProperty() {
		return null;
	}

	@Override
	protected String doGetDefaultProfilesProperty() {
		return null;
	}

	@Override
	protected ConfigurablePropertyResolver createPropertyResolver(MutablePropertySources propertySources) {
		// 创建属性解析器
		return ConfigurationPropertySources.createPropertyResolver(propertySources);
	}

}

上面两种Environment都只是重写了createPropertyResolver方法,而且实现一样,为什么需要实现子类,而且需要实现两个不同的类?可能的原因如下:

  • 因为Spring Framework中的Environment并没有提供setPropertyResolver方法,而且外部也无法修改propertyResolver属性,所以只能实现子类来重写createPropertyResolver方法。
  • servlet和reactive的environment是不同的类,也许是为后续的扩展留下空间。
v2.7.x
createPropertyResolver
ConfigurationPropertySourcesPropertyResolver
<
>
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySources.java
public static ConfigurablePropertyResolver createPropertyResolver(MutablePropertySources propertySources) {
    return new ConfigurationPropertySourcesPropertyResolver(propertySources);
}
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertyResolver.java
ConfigurationPropertySourcesPropertyResolver(MutablePropertySources propertySources) {
    this.propertySources = propertySources;
    // 创建默认的解析器
    this.defaultResolver = new DefaultResolver(propertySources);
}
/**
 * Default {@link PropertySourcesPropertyResolver} used if
 * {@link ConfigurationPropertySources} is not attached.
 */
// 这里的实现有什么意义?为什么不直接使用PropertySourcesPropertyResolver?
static class DefaultResolver extends PropertySourcesPropertyResolver {

    DefaultResolver(PropertySources propertySources) {
        super(propertySources);
    }

    @Override
    public <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
        return super.getProperty(key, targetValueType, resolveNestedPlaceholders);
    }

}

这里并没有使用默认的属性解析器PropertySourcesPropertyResolver,而是ConfigurationPropertySourcesPropertyResolver。后者采用委托模式,组合了真正的属性解析器DefaultResolverDefaultResolver继承于PropertySourcesPropertyResolver, 是ConfigurationPropertySourcesPropertyResolver中的内部类。

configureEnvironment方法

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
    // 该属性默认为true
    if (this.addConversionService) {
        // 设置转换服务,用于转换属性,比如替换属性中的占位符
        environment.setConversionService(new ApplicationConversionService());
    }
    // 设置属性源
    configurePropertySources(environment, args);
    // 设置Profiles,默认是空操作
    configureProfiles(environment, args);
}

设置ConversionService

这里创建了一个转换服务对象,并设置到environment中的属性解析器中。在属性解析器解析属性时,如果需要对属性值进行转换,那么会调用转换服务。 这里创建的是ApplicationConversionService,会添加一些默认和预定义的转换器和格式化器。

v2.7.x
constructors
configure
addApplicationConverters
addApplicationFormatters
<
>
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java
public ApplicationConversionService() {
    this(null);
}

public ApplicationConversionService(StringValueResolver embeddedValueResolver) {
    this(embeddedValueResolver, false);
}

private ApplicationConversionService(StringValueResolver embeddedValueResolver, boolean unmodifiable) {
    if (embeddedValueResolver != null) {
        setEmbeddedValueResolver(embeddedValueResolver);
    }
    configure(this);
    this.unmodifiable = unmodifiable;
}
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java
public static void configure(FormatterRegistry registry) {
    // 添加默认的转换器
    DefaultConversionService.addDefaultConverters(registry);
    // 添加默认的格式化器
    DefaultFormattingConversionService.addDefaultFormatters(registry);
    // 添加格式化器
    addApplicationFormatters(registry);
    // 添加转换器
    addApplicationConverters(registry);
}
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java
public static void addApplicationConverters(ConverterRegistry registry) {
    addDelimitedStringConverters(registry);
    registry.addConverter(new StringToDurationConverter());
    registry.addConverter(new DurationToStringConverter());
    registry.addConverter(new NumberToDurationConverter());
    registry.addConverter(new DurationToNumberConverter());
    registry.addConverter(new StringToPeriodConverter());
    registry.addConverter(new PeriodToStringConverter());
    registry.addConverter(new NumberToPeriodConverter());
    registry.addConverter(new StringToDataSizeConverter());
    registry.addConverter(new NumberToDataSizeConverter());
    registry.addConverter(new StringToFileConverter());
    registry.addConverter(new InputStreamSourceToByteArrayConverter());
    registry.addConverterFactory(new LenientStringToEnumConverterFactory());
    registry.addConverterFactory(new LenientBooleanToEnumConverterFactory());
    if (registry instanceof ConversionService) {
        addApplicationConverters(registry, (ConversionService) registry);
    }
}

private static void addApplicationConverters(ConverterRegistry registry, ConversionService conversionService) {
    registry.addConverter(new CharSequenceToObjectConverter(conversionService));
}
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java
public static void addApplicationFormatters(FormatterRegistry registry) {
    registry.addFormatter(new CharArrayFormatter());
    registry.addFormatter(new InetAddressFormatter());
    registry.addFormatter(new IsoOffsetFormatter());
}

configure方法中,添加了默认的转换器和格式化器。那两个类是Spring Framework中的,这里就不贴出代码了,逻辑很简单,就是添加了一系列组件。在涉及到具体的类型转换和格式化问题时再有针对性地分析问题。

设置命令行参数属性源

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
    // 从environment对象中获取属性源,==== 该方法的目的是把命令行参数注入到environment的属性中 ====
    MutablePropertySources sources = environment.getPropertySources();
    // 如果默认属性配置存在,则将其追加在sources对象中
    if (!CollectionUtils.isEmpty(this.defaultProperties)) {
        DefaultPropertiesPropertySource.addOrMerge(this.defaultProperties, sources);
    }
    // addCommandLineProperties属性默认为true
    /*
     * 注意,下面调用的SimpleCommandLinePropertySource构造器内部会对args进行解析
     * 也可以发现其处理参数的顺序,命令行参数会被放在第一个的位置
     */
    if (this.addCommandLineProperties && args.length > 0) {
        String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
        if (sources.contains(name)) { // 如果存在名为commandLineArgs的属性
            PropertySource<?> source = sources.get(name);
            CompositePropertySource composite = new CompositePropertySource(name);
            /*
             * 这里创建名称为springApplicationCommandLineArgs的命令行属性源,
             * 然后作为属性源添加到复合属性源中
             */
            composite.addPropertySource(
                    new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
            // 继续添加已存在的属性源
            composite.addPropertySource(source);
            // 替换已存在的同名属性源
            sources.replace(name, composite);
        }
        else { // 如果不存在名为commandLineArgs的配置,则创建一个,并放在sources中的第一个位置
            // 使用默认名称commandLineArgs
            sources.addFirst(new SimpleCommandLinePropertySource(args));
        }
    }
}

ConfigurationPropertySources.attach方法

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySources.java
private static final String ATTACHED_PROPERTY_SOURCE_NAME = "configurationProperties";
public static void attach(Environment environment) {
    // 要求environment必须是可配置的
    Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
    // 获取environment中的所有属性源
    MutablePropertySources sources = ((ConfigurableEnvironment) environment).getPropertySources();
    // 获取名为configurationProperties的属性源
    PropertySource<?> attached = getAttached(sources);
    // 如果attached这个属性源不存在,或者所封装的source不是environment中的属性源,那么新建一个对象。
    if (attached == null || !isUsingSources(attached, sources)) {
        // 创建新的配置属性源对象
        attached = new ConfigurationPropertySourcesPropertySource(ATTACHED_PROPERTY_SOURCE_NAME,
                // 将其他属性源封装为一个Spring的配置属性源
                new SpringConfigurationPropertySources(sources));
    }
    // 从原有的属性源列表中移除掉
    sources.remove(ATTACHED_PROPERTY_SOURCE_NAME);
    // 将配置属性源添加到列表中的第一个
    sources.addFirst(attached);
}
private static boolean isUsingSources(PropertySource<?> attached, MutablePropertySources sources) {
    return attached instanceof ConfigurationPropertySourcesPropertySource
            // 这里是在判断attached这个属性源封装的source和参数sources是否是同一个对象
            && ((SpringConfigurationPropertySources) attached.getSource()).isUsingSources(sources);
}
static PropertySource<?> getAttached(MutablePropertySources sources) {
    // 从属性源集合中获取名为configurationProperties的属性源
    return (sources != null) ? sources.get(ATTACHED_PROPERTY_SOURCE_NAME) : null;
}

prepareEnvironment方法中调用了两次该方法,第二次调用是确保配置属性源(configurationPropertySource)位于属性源列表中的第一个,因为可能在environmentPrepared事件的处理中往属性源列表头部添加其他属性源。

environmentPrepared事件

事件的发起和广播的代码请参考上面介绍的SpringApplicationRunListeners,不再赘述。这里重点关注一个与environment相关的监听器:EnvironmentPostProcessorApplicationListener

EnvironmentPostProcessorApplicationListener

构造器

在其构造器中,加载了预配置的EnvironmentPostProcessor类型。

v2.7.x
EnvironmentPostProcessorApplicationListener
fromSpringFactories
ReflectionEnvironmentPostProcessorsFactory
<
>
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/EnvironmentPostProcessorApplicationListener.java
public EnvironmentPostProcessorApplicationListener() {
    this(EnvironmentPostProcessorsFactory::fromSpringFactories, new DeferredLogs());
}

/**
 * Create a new {@link EnvironmentPostProcessorApplicationListener} with post
 * processors created by the given factory.
 * @param postProcessorsFactory the post processors factory
 */
public EnvironmentPostProcessorApplicationListener(EnvironmentPostProcessorsFactory postProcessorsFactory) {
    this((classloader) -> postProcessorsFactory, new DeferredLogs());
}

EnvironmentPostProcessorApplicationListener(
        Function<ClassLoader, EnvironmentPostProcessorsFactory> postProcessorsFactory, DeferredLogs deferredLogs) {
    this.postProcessorsFactory = postProcessorsFactory;
    this.deferredLogs = deferredLogs;
}
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/EnvironmentPostProcessorsFactory.java
static EnvironmentPostProcessorsFactory fromSpringFactories(ClassLoader classLoader) {
    return new ReflectionEnvironmentPostProcessorsFactory(classLoader,
            SpringFactoriesLoader.loadFactoryNames(EnvironmentPostProcessor.class, classLoader));
}
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/ReflectionEnvironmentPostProcessorsFactory.java
private final List<Class<?>> classes;

private ClassLoader classLoader;

private final List<String> classNames;
ReflectionEnvironmentPostProcessorsFactory(Class<?>... classes) {
    this.classes = new ArrayList<>(Arrays.asList(classes));
    this.classNames = null;
}

ReflectionEnvironmentPostProcessorsFactory(ClassLoader classLoader, String... classNames) {
    this(classLoader, Arrays.asList(classNames));
}

ReflectionEnvironmentPostProcessorsFactory(ClassLoader classLoader, List<String> classNames) {
    this.classes = null;
    this.classLoader = classLoader;
    this.classNames = classNames;
}

预配置的EnvironmentPostProcessor如下:

v2.7.x
properties
spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor,\
org.springframework.boot.env.RandomValuePropertySourceEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\
org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor

事件处理

v2.7.x
handle event
getEnvironmentPostProcessors
Instantiator
<
>
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/EnvironmentPostProcessorApplicationListener.java
@Override
public void onApplicationEvent(ApplicationEvent event) {
    if (event instanceof ApplicationEnvironmentPreparedEvent) {
        onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
    }
    if (event instanceof ApplicationPreparedEvent) {
        onApplicationPreparedEvent();
    }
    if (event instanceof ApplicationFailedEvent) {
        onApplicationFailedEvent();
    }
}
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
    ConfigurableEnvironment environment = event.getEnvironment();
    SpringApplication application = event.getSpringApplication();
    // 获取并遍历后置处理器
    for (EnvironmentPostProcessor postProcessor : getEnvironmentPostProcessors(application.getResourceLoader(),
            event.getBootstrapContext())) {
        // 后置处理
        postProcessor.postProcessEnvironment(environment, application);
    }
}
List<EnvironmentPostProcessor> getEnvironmentPostProcessors(ResourceLoader resourceLoader,
        ConfigurableBootstrapContext bootstrapContext) {
    ClassLoader classLoader = (resourceLoader != null) ? resourceLoader.getClassLoader() : null;
    EnvironmentPostProcessorsFactory postProcessorsFactory = this.postProcessorsFactory.apply(classLoader);
    // 获取后置处理器
    return postProcessorsFactory.getEnvironmentPostProcessors(this.deferredLogs, bootstrapContext);
}
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/ReflectionEnvironmentPostProcessorsFactory.java
@Override
public List<EnvironmentPostProcessor> getEnvironmentPostProcessors(DeferredLogFactory logFactory,
        ConfigurableBootstrapContext bootstrapContext) {
    // 创建实例化器,用于实例化预配置的environment后置处理器类
    Instantiator<EnvironmentPostProcessor> instantiator = new Instantiator<>(EnvironmentPostProcessor.class,
            (parameters) -> {
                parameters.add(DeferredLogFactory.class, logFactory);
                parameters.add(Log.class, logFactory::getLog);
                parameters.add(ConfigurableBootstrapContext.class, bootstrapContext);
                parameters.add(BootstrapContext.class, bootstrapContext);
                parameters.add(BootstrapRegistry.class, bootstrapContext);
            });
    return (this.classes != null) ? instantiator.instantiateTypes(this.classes)
            // 创建classNames中的类型对应的实例
            : instantiator.instantiate(this.classLoader, this.classNames);
}
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/util/Instantiator.java
public class Instantiator<T> {

	private static final Comparator<Constructor<?>> CONSTRUCTOR_COMPARATOR = Comparator
			.<Constructor<?>>comparingInt(Constructor::getParameterCount).reversed();

	private static final FailureHandler throwingFailureHandler = (type, implementationName, failure) -> {
		throw new IllegalArgumentException("Unable to instantiate " + implementationName + " [" + type.getName() + "]",
				failure);
	};

	private final Class<?> type;

	private final Map<Class<?>, Function<Class<?>, Object>> availableParameters;

	private final FailureHandler failureHandler;

	/**
	 * Create a new {@link Instantiator} instance for the given type.
	 * @param type the type to instantiate
	 * @param availableParameters consumer used to register available parameters
	 */
	public Instantiator(Class<?> type, Consumer<AvailableParameters> availableParameters) {
		this(type, availableParameters, throwingFailureHandler);
	}

	/**
	 * Create a new {@link Instantiator} instance for the given type.
	 * @param type the type to instantiate
	 * @param availableParameters consumer used to register available parameters
	 * @param failureHandler a {@link FailureHandler} that will be called in case of
	 * failure when instantiating objects
	 * @since 2.7.0
	 */
	public Instantiator(Class<?> type, Consumer<AvailableParameters> availableParameters,
			FailureHandler failureHandler) {
		this.type = type;
		this.availableParameters = getAvailableParameters(availableParameters);
		this.failureHandler = failureHandler;
	}

	private Map<Class<?>, Function<Class<?>, Object>> getAvailableParameters(
			Consumer<AvailableParameters> availableParameters) {
		Map<Class<?>, Function<Class<?>, Object>> result = new LinkedHashMap<>();
		availableParameters.accept(new AvailableParameters() {

			@Override
			public void add(Class<?> type, Object instance) {
				result.put(type, (factoryType) -> instance);
			}

			@Override
			public void add(Class<?> type, Function<Class<?>, Object> factory) {
				result.put(type, factory);
			}

		});
		return Collections.unmodifiableMap(result);
	}

	/*
	 * 注意下面的几个instantiate重载方法调用顺序是依次往后
	 */

	/**
	 * Instantiate the given set of class name, injecting constructor arguments as
	 * necessary.
	 * @param names the class names to instantiate
	 * @return a list of instantiated instances
	 */
	public List<T> instantiate(Collection<String> names) {
		return instantiate((ClassLoader) null, names);
	}

	/**
	 * Instantiate the given set of class name, injecting constructor arguments as
	 * necessary.
	 * @param classLoader the source classloader
	 * @param names the class names to instantiate
	 * @return a list of instantiated instances
	 * @since 2.4.8
	 */
	public List<T> instantiate(ClassLoader classLoader, Collection<String> names) {
		Assert.notNull(names, "Names must not be null");
		return instantiate(names.stream().map((name) -> TypeSupplier.forName(classLoader, name)));
	}

	/**
	 * Instantiate the given set of classes, injecting constructor arguments as necessary.
	 * @param types the types to instantiate
	 * @return a list of instantiated instances
	 * @since 2.4.8
	 */
	public List<T> instantiateTypes(Collection<Class<?>> types) {
		Assert.notNull(types, "Types must not be null");
		return instantiate(types.stream().map(TypeSupplier::forType));
	}

	private List<T> instantiate(Stream<TypeSupplier> typeSuppliers) {
		List<T> instances = typeSuppliers.map(this::instantiate).collect(Collectors.toList());
		AnnotationAwareOrderComparator.sort(instances);
		return Collections.unmodifiableList(instances);
	}

	private T instantiate(TypeSupplier typeSupplier) {
		try {
			Class<?> type = typeSupplier.get();
			Assert.isAssignable(this.type, type);
			// 创建实例对象,调用下一个instantiate重载方法
			return instantiate(type);
		}
		catch (Throwable ex) {
			this.failureHandler.handleFailure(this.type, typeSupplier.getName(), ex);
			return null;
		}
	}

	@SuppressWarnings("unchecked")
	private T instantiate(Class<?> type) throws Exception {
		Constructor<?>[] constructors = type.getDeclaredConstructors();
		Arrays.sort(constructors, CONSTRUCTOR_COMPARATOR);
		for (Constructor<?> constructor : constructors) {
			// 获取构造方法参数列表
			Object[] args = getArgs(constructor.getParameterTypes());
			if (args != null) {
				ReflectionUtils.makeAccessible(constructor);
				// 创建实例对象
				return (T) constructor.newInstance(args);
			}
		}
		throw new IllegalAccessException("Class [" + type.getName() + "] has no suitable constructor");
	}

	private Object[] getArgs(Class<?>[] parameterTypes) {
		Object[] args = new Object[parameterTypes.length];
		// 遍历构造方法参数类型
		for (int i = 0; i < parameterTypes.length; i++) {
			// 获取可用的参数
			Function<Class<?>, Object> parameter = getAvailableParameter(parameterTypes[i]);
			if (parameter == null) {
				return null;
			}
			// 获取实际的参数值
			args[i] = parameter.apply(this.type);
		}
		return args;
	}

	private Function<Class<?>, Object> getAvailableParameter(Class<?> parameterType) {
		// 遍历所有的可用参数
		for (Map.Entry<Class<?>, Function<Class<?>, Object>> entry : this.availableParameters.entrySet()) {
			// 如果可用参数的类型是目标类型及其子类型,
			if (entry.getKey().isAssignableFrom(parameterType)) {
				// 则返回对应的参数值对象
				return entry.getValue();
			}
		}
		return null;
	}

	/**
	 * Callback used to register available parameters.
	 */
	public interface AvailableParameters {

		/**
		 * Add a parameter with an instance value.
		 * @param type the parameter type
		 * @param instance the instance that should be injected
		 */
		void add(Class<?> type, Object instance);

		/**
		 * Add a parameter with an instance factory.
		 * @param type the parameter type
		 * @param factory the factory used to create the instance that should be injected
		 */
		void add(Class<?> type, Function<Class<?>, Object> factory);

	}

	/**
	 * {@link Supplier} that provides a class type.
	 */
	private interface TypeSupplier {

		String getName();

		Class<?> get() throws ClassNotFoundException;

		static TypeSupplier forName(ClassLoader classLoader, String name) {
			return new TypeSupplier() {

				@Override
				public String getName() {
					return name;
				}

				@Override
				public Class<?> get() throws ClassNotFoundException {
					return ClassUtils.forName(name, classLoader);
				}

			};
		}

		static TypeSupplier forType(Class<?> type) {
			return new TypeSupplier() {

				@Override
				public String getName() {
					return type.getName();
				}

				@Override
				public Class<?> get() throws ClassNotFoundException {
					return type;
				}

			};
		}

	}

	/**
	 * Strategy for handling a failure that occurs when instantiating a type.
	 *
	 * @since 2.7.0
	 */
	public interface FailureHandler {

		/**
		 * Handle the {@code failure} that occurred when instantiating the {@code type}
		 * that was expected to be of the given {@code typeSupplier}.
		 * @param type the type
		 * @param implementationName the name of the implementation type
		 * @param failure the failure that occurred
		 */
		void handleFailure(Class<?> type, String implementationName, Throwable failure);

	}

}

这里省略各个environment后置处理器的后置逻辑,需要单独写文章来介绍。

DefaultPropertiesPropertySource.moveToEnd 方法

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/DefaultPropertiesPropertySource.java
public static final String NAME = "defaultProperties";
public static void moveToEnd(ConfigurableEnvironment environment) {
    moveToEnd(environment.getPropertySources());
}
public static void moveToEnd(MutablePropertySources propertySources) {
    // 移除默认属性源
    PropertySource<?> propertySource = propertySources.remove(NAME);
    if (propertySource != null) {
        // 将默认属性源添加到列表末尾
        propertySources.addLast(propertySource);
    }
}

这部分的逻辑比较简单,就是把environment对象中名称为”defaultProperties“的属性源移动到列表末尾。

bindToSpringApplication方法

该方法主要是将当前的environment对象中的以spring.main开头的属性绑定到当前SpringApplication实例上。

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
protected void bindToSpringApplication(ConfigurableEnvironment environment) {
    try {
        // 将spring.main开头的属性办定到当前类实例中
        Binder.get(environment).bind("spring.main", Bindable.ofInstance(this));
    }
    catch (Exception ex) {
        throw new IllegalStateException("Cannot bind to SpringApplication", ex);
    }
}

由于Binder的逻辑比较复杂,代码量较多,所以这里暂时省略,后续新写一篇文章来总结。

转换environment对象

由于是可以在SpringApplication外部设置environment对象的,所以如果不需要自定义environment的情况下,Spring Boot默认会将environment对象转换为根据应用类型而自动推断出来的Environment类型。

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/EnvironmentConverter.java
StandardEnvironment convertEnvironmentIfNecessary(ConfigurableEnvironment environment,
        Class<? extends StandardEnvironment> type) {
    // 如果environment对象就是目标类型的实例,
    if (type.equals(environment.getClass())) {
        // 则直接转换
        return (StandardEnvironment) environment;
    }
    // 转换environment对象
    return convertEnvironment(environment, type);
}
private StandardEnvironment convertEnvironment(ConfigurableEnvironment environment,
        Class<? extends StandardEnvironment> type) {
    // 创建目标类型的Environment实例
    StandardEnvironment result = createEnvironment(type);
    // 设置激活的profiles
    result.setActiveProfiles(environment.getActiveProfiles());
    // 设置转换服务
    result.setConversionService(environment.getConversionService());
    // 复制属性源
    copyPropertySources(environment, result);
    return result;
}

spring.beaninfo.ignore属性设置

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
    // 如果不存在名为spring.beaninfo.ignore的系统属性,那么从environment中获取然后设置到系统属性中
    if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
        // 从environment中获取属性
        Boolean ignore = environment.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME,
                Boolean.class, Boolean.TRUE);
        // 设置到系统属性中
        System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString());
    }
}

应用上下文

接下来

createApplicationContext方法

v2.7.x
createApplicationContext
default factory
<
>
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
private ApplicationContextFactory applicationContextFactory = ApplicationContextFactory.DEFAULT;
protected ConfigurableApplicationContext createApplicationContext() {
    /*
     * applicationContextFactory的默认值是ApplicationContextFactory.DEFAULT,
     * 但也可以通过setApplicationContextFactory方法来设置
     */
    return this.applicationContextFactory.create(this.webApplicationType);
}
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ApplicationContextFactory.java
ApplicationContextFactory DEFAULT = (webApplicationType) -> {
    try {
        // 默认配置了两个,分别对应Servlet类型和Reactive类型的web应用
        for (ApplicationContextFactory candidate : SpringFactoriesLoader
                .loadFactories(ApplicationContextFactory.class, ApplicationContextFactory.class.getClassLoader())) {
            // 这里把web应用类型传进去,里面会基于web应用类型判断是否创建容器,类型不匹配的话会返回null
            ConfigurableApplicationContext context = candidate.create(webApplicationType);
            if (context != null) {
                return context;
            }
        }
        // 非web类型
        return new AnnotationConfigApplicationContext();
    }
    catch (Exception ex) {
        throw new IllegalStateException("Unable create a default ApplicationContext instance, "
                + "you may need a custom ApplicationContextFactory", ex);
    }
};

这里会加载预配置好的应用上下文工厂类:

v2.7.x
properties
spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories
# Application Context Factories
org.springframework.boot.ApplicationContextFactory=\
org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext.Factory,\
org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext.Factory

下面分别是两种应用上下文工厂的实现:

v2.7.x
servlet
reactive
<
>
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/context/AnnotationConfigServletWebServerApplicationContext.java
static class Factory implements ApplicationContextFactory {

    // 创建servlet应用上下文实例
    @Override
    public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
        return (webApplicationType != WebApplicationType.SERVLET) ? null
                : new AnnotationConfigServletWebServerApplicationContext();
    }

}
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/AnnotationConfigReactiveWebServerApplicationContext.java
static class Factory implements ApplicationContextFactory {

    @Override
    public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
        return (webApplicationType != WebApplicationType.REACTIVE) ? null
                // 创建容器上下文
                : new AnnotationConfigReactiveWebServerApplicationContext();
    }

}

prepareContext方法

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
        ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments, Banner printedBanner) {
    // 应用上下文关联environment对象
    context.setEnvironment(environment);
    // 应用上下文后置处理
    postProcessApplicationContext(context);
    // 执行应用上下文初始化器
    applyInitializers(context);
    /*
     * 事件通知
     * 在Spring Cloud中会执行到BootstrapApplicationListener
     */
    listeners.contextPrepared(context);
    // 关闭启动上下文
    bootstrapContext.close(context);
    if (this.logStartupInfo) {
        logStartupInfo(context.getParent() == null); // 打印启动日志
        logStartupProfileInfo(context); // 打印profile日志
    }
    // Add boot specific singleton beans
    // 获取beanFactory并注册springApplicationArguments、 printedBanner为单例bean,另外还设置是否允许循环依赖、是否允许覆盖beanDefinition的属性
    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    if (printedBanner != null) {
        beanFactory.registerSingleton("springBootBanner", printedBanner);
    }
    if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
        // 设置是否允许循环依赖, 默认为false (boolean类型的默认值)。
        ((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
        if (beanFactory instanceof DefaultListableBeanFactory) {
            // 设置是否允许覆盖beanDefinition的属性
            ((DefaultListableBeanFactory) beanFactory)
                    .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
    }

    // 下面添加bean工厂后置处理器
    if (this.lazyInitialization) {
        context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
    }
    context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
    // Load the sources
    // 获取全部配置源
    Set<Object> sources = getAllSources();
    Assert.notEmpty(sources, "Sources must not be empty");
    // 将配置源中的bean注册到beanFactory中
    load(context, sources.toArray(new Object[0]));
    // 广播应用上下文加载完成事件
    listeners.contextLoaded(context);
}

大部分步骤都很简单,主要分析一下后置处理器和初始化器的执行。

postProcessApplicationContext方法

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
private boolean addConversionService = true;
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
    // 如果存在beanNameGenerator,那么注册到beanFactory上
    if (this.beanNameGenerator != null) {
        context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
                this.beanNameGenerator);
    }
    // 如果存在resourceLoader,那么注册到applicationContext上
    if (this.resourceLoader != null) {
        if (context instanceof GenericApplicationContext) {
            ((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
        }
        if (context instanceof DefaultResourceLoader) {
            ((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
        }
    }
    // (addConversionService默认为true)注册转换服务
    if (this.addConversionService) {
        context.getBeanFactory().setConversionService(context.getEnvironment().getConversionService());
    }
}

applyInitializers方法

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
@SuppressWarnings({ "rawtypes", "unchecked" })
protected void applyInitializers(ConfigurableApplicationContext context) {
    // 遍历应用上下文初始化器
    for (ApplicationContextInitializer initializer : getInitializers()) {
        // 获取当前initializer的泛型参数(这里是怎么获取到泛型参数的?)
        Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
                ApplicationContextInitializer.class);
        // 断言泛型参数和context的类型是否匹配
        Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
        // 初始化context
        initializer.initialize(context);
    }
}
public Set<ApplicationContextInitializer<?>> getInitializers() {
    return asUnmodifiableOrderedSet(this.initializers);
}

这里执行的ApplicationContextInitializerSpringApplication构造时从预配置文件中加载并实例化的。

v2.7.x
properties
spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories
# 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

refreshContext方法

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
static final SpringApplicationShutdownHook shutdownHook = new SpringApplicationShutdownHook();
private void refreshContext(ConfigurableApplicationContext context) {
    if (this.registerShutdownHook) {
        shutdownHook.registerApplicationContext(context);
    }
    // 刷新上下文
    refresh(context);
}
protected void refresh(ConfigurableApplicationContext applicationContext) {
    /*
     * 这里没有直接调用AbstractApplicationContext的refresh方法,
     * 而是调用的ConfigurableApplicationContext(直接继承ApplicationContext)的refresh方法。
     * 其有两个子类重写了该方法,在重写的方法中再调用的AbstractApplicationContext的refresh方法。
     */
    applicationContext.refresh();
}

执行Runners

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
private void callRunners(ApplicationContext context, ApplicationArguments args) {
    List<Object> runners = new ArrayList<>();
    // 分别从应用上下文中获取ApplicationRunner和CommandLineRunner类型的bean
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    // 对其进行排序
    AnnotationAwareOrderComparator.sort(runners);
    // 遍历runner
    for (Object runner : new LinkedHashSet<>(runners)) {
        if (runner instanceof ApplicationRunner) {
            // 调用ApplicationRunner
            callRunner((ApplicationRunner) runner, args);
        }
        if (runner instanceof CommandLineRunner) {
            // 调用CommandLineRunner
            callRunner((CommandLineRunner) runner, args);
        }
    }
}

private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
    try {
        (runner).run(args);
    }
    catch (Exception ex) {
        throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
    }
}

private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
    try {
        (runner).run(args.getSourceArgs());
    }
    catch (Exception ex) {
        throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
    }
}

总结

本文篇幅较长,主要的重点是Environment对象的处理和ApplicationContext的处理。Spring Boot的启动流程中涉及很多事件的发布,很多扩展都是基于这些事件来实现的,后续单独写文章来总结每种扩展点。