深入SpringBoot源码(三)prepareEnvironment前的操作

SpringApplication的run方法

SpringApplication的run方法运行 Spring 应用程序,创建并刷新一个新的ApplicationContext。

	public ConfigurableApplicationContext run(String... args) {
		long startTime = System.nanoTime();
		DefaultBootstrapContext bootstrapContext = createBootstrapContext();
		ConfigurableApplicationContext context = null;
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting(bootstrapContext, this.mainApplicationClass);
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			context.setApplicationStartup(this.applicationStartup);
			prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
			}
			listeners.started(context, timeTakenToStartup);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}
		try {
			Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
			listeners.ready(context, timeTakenToReady);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

System.nanoTime()

在这里插入图片描述
定义了startTime用于记录run方法开始的时间

createBootstrapContext()

createBootstrapContext()用于创建BootstrapContext实例
在这里插入图片描述

	private DefaultBootstrapContext createBootstrapContext() {
		DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
		this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
		return bootstrapContext;
	}

DefaultBootstrapContext是默认ConfigurableBootstrapContext实现。ConfigurableBootstrapContext是一个BootstrapContext ,它还通过BootstrapRegistry接口提供配置方法。

public interface ConfigurableBootstrapContext extends BootstrapRegistry, BootstrapContext {

}

BootstrapContext是一个简单的引导上下文,在启动和Environment后处理期间可用,直到准备好ApplicationContext。BootstrapContext提供对单例的惰性访问,这些单例的创建成本可能很高,或者需要在ApplicationContext可用之前共享。

public interface BootstrapContext {

	/**
	 * 如果类型已注册,则从上下文中返回一个实例。如果之前没有访问过该实例,则会创建它。
	 * @param <T> 实例类型
	 * @param type 实例类型
	 * @throws IllegalStateException 如果类型尚未注册
	 */
	<T> T get(Class<T> type) throws IllegalStateException;

	/**
	 * 如果类型已注册,则从上下文中返回一个实例。如果之前没有访问过该实例,则会创建它。
	 * @param <T> 实例类型
	 * @param type 实例类型
	 * @param other 如果类型尚未注册,则使用的实例
	 */
	<T> T getOrElse(Class<T> type, T other);

	/**
	 * 如果类型已注册,则从上下文中返回一个实例。如果之前没有访问过该实例,则会创建它。
	 * @param <T> 实例类型
	 * @param type 实例类型
	 * @param other 如果类型尚未注册,则要使用的实例的Supplier
	 */
	<T> T getOrElseSupply(Class<T> type, Supplier<T> other);

	/**
	 * 如果类型已注册,则从上下文中返回一个实例。如果之前没有访问过该实例,则会创建它。
	 * @param <T> 实例类型
	 * @param type 实例类型
	 * @param exceptionSupplier 将返回要抛出的异常的Supplier
	 * @throws IllegalStateException 如果类型尚未注册抛出的异常
	 */
	<T, X extends Throwable> T getOrElseThrow(Class<T> type, Supplier<? extends X> exceptionSupplier) throws X;

	/**
	 * 如果给定类型存在注册,则返回true。
	 * @param <T> 实例类型
	 * @param type 实例类型
	 */
	<T> boolean isRegistered(Class<T> type);

}

在引入依赖的spring.factories中不包含BootstrapRegistryInitializer的实例,所以得到的BootstrapContext内容如下:
在这里插入图片描述

configureHeadlessProperty()

在这里插入图片描述

	private void configureHeadlessProperty() {
		System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
				System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
	}

configureHeadlessProperty设置系统属性java.awt.headless的值,如果原先没有设置,则设置为true。

getRunListeners(String[] args)

在这里插入图片描述

	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger,
				getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
				this.applicationStartup);
	}

SpringApplicationRunListeners是SpringApplicationRunListener的集合,SpringApplicationRunListener是SpringApplication run方法的侦听器。 SpringApplicationRunListener通过SpringFactoriesLoader加载,并且应该声明一个接受SpringApplication实例和String[]参数的公共构造函数。每次运行都会创建一个新的SpringApplicationRunListener实例。

public interface SpringApplicationRunListener {

	/**
	 * 在 run 方法第一次启动时立即调用。可用于非常早的初始化。
	 */
	default void starting(ConfigurableBootstrapContext bootstrapContext) {
	}

	/**
	 * 在环境准备好,且在创建ApplicationContext之前调用。
	 */
	default void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
			ConfigurableEnvironment environment) {
	}

	/**
	 * 在创建和准备ApplicationContext后,但在加载源之前调用。
	 */
	default void contextPrepared(ConfigurableApplicationContext context) {
	}

	/**
	 * 在加载应用程序上下文但在刷新之前调用。
	 */
	default void contextLoaded(ConfigurableApplicationContext context) {
	}

	/**
	 * 上下文已刷新,应用程序已启动,但尚未调用CommandLineRunners和ApplicationRunners。
	 * @param timeTaken 启动应用程序所用的时间,如果未知,则为null
	 * @since 2.6.0
	 */
	default void started(ConfigurableApplicationContext context, Duration timeTaken) {
		started(context);
	}

	/**
	 * 上下文已刷新,应用程序已启动,但尚未调用CommandLineRunners和ApplicationRunners。
	 */
	@Deprecated
	default void started(ConfigurableApplicationContext context) {
	}

	/**
	 * 在 run 方法完成之前立即调用,此时应用程序上下文已刷新并且所有CommandLineRunners和ApplicationRunners已被调用。
	 * @param timeTaken 启动应用程序所用的时间,如果未知,则为null
	 * @since 2.6.0
	 */
	default void ready(ConfigurableApplicationContext context, Duration timeTaken) {
		running(context);
	}

	/**
	 * 在 run 方法完成之前立即调用,此时应用程序上下文已刷新并且所有CommandLineRunners和ApplicationRunners已被调用。
	 */
	@Deprecated
	default void running(ConfigurableApplicationContext context) {
	}

	/**
	 * 当运行应用程序发生故障时调用。
	 * @since 2.0.0
	 */
	default void failed(ConfigurableApplicationContext context, Throwable exception) {
	}

}

listeners.starting(bootstrapContext, this.mainApplicationClass)

在这里插入图片描述

	void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
		doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
				(step) -> {
					if (mainApplicationClass != null) {
						step.tag("mainApplicationClass", mainApplicationClass.getName());
					}
				});
	}
	private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
			Consumer<StartupStep> stepAction) {
		StartupStep step = this.applicationStartup.start(stepName);
		this.listeners.forEach(listenerAction);
		if (stepAction != null) {
			stepAction.accept(step);
		}
		step.end();
	}

StartupStep记录有关在ApplicationStartup期间发生的特定阶段或操作的指标。StartupStep的生命周期如下:1.该步骤是通过调用the application startup来创建和启动的,并被分配一个唯一的id。2.我们可以在处理过程中使用StartupStep.Tags附加信息。3.我们需要标记步骤的end()。
实现可以跟踪“执行时间”或其他步骤的度量。

public interface StartupStep {

	/**
	 * 返回启动步骤的名称。
	 */
	String getName();

	/**
	 * 在应用程序启动中返回此步骤的唯一 ID。
	 */
	long getId();

	/**
	 * 如果可用,返回父步骤的id。父步骤是创建当前步骤时最近启动的步骤。
	 */
	@Nullable
	Long getParentId();

	/**
	 * 将StartupStep.Tag添加到步骤。
	 */
	StartupStep tag(String key, String value);

	/**
	 * 将StartupStep.Tag添加到步骤。
	 */
	StartupStep tag(String key, Supplier<String> value);

	/**
	 * 返回此步骤的StartupStep.Tag集合。
	 */
	Tags getTags();

	/**
	 * 记录步骤的状态以及可能的其他指标,例如执行时间。一旦结束,就不允许更改步骤状态。
	 */
	void end();


	/**
	 * StartupStep.Tag的不可变集合。
	 */
	interface Tags extends Iterable<Tag> {
	}


	/**
	 * 用于存储步骤元数据的简单键/值关联。
	 */
	interface Tag {

		/**
		 * 返回Tag名称。
		 */
		String getKey();

		/**
		 * 返回Tag值。
		 */
		String getValue();
	}

}

执行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值