【SpringBoot3.0ソースコード】スタートプロセスのソースコード解析

前回の記事「【SpringBoot3.0ソースコード】起動処理ソースコード解析・その1」では、イニシャライザとリスナの設定方法を中心に説明しましたがnew SpringApplication()、続いてメソッドの呼び出し方法について説明しますrun

run メソッドにステップインします。

ここに画像の説明を挿入

public ConfigurableApplicationContext run(String... args) {
    
    
	// 记录时间
	long startTime = System.nanoTime();
	// 利用BootstrapRegistryInitializer初始化DefaultBootstrapContext对象
	DefaultBootstrapContext bootstrapContext = createBootstrapContext();
	ConfigurableApplicationContext context = null;
	// 开启了Headless模式
	configureHeadlessProperty();
	// 获取监听器
	SpringApplicationRunListeners listeners = getRunListeners(args);
	// 发布ApplicationStartingEvent事件
	listeners.starting(bootstrapContext, this.mainApplicationClass);
	try {
    
    
		// 根据命令行参数,实例化一个ApplicationArguments
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
		// 准备环境
		ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
		// 打印Banner
		Banner printedBanner = printBanner(environment);
		// 据webApplicationType创建不同的Spring上下文容器(有三种)
		context = createApplicationContext();
		context.setApplicationStartup(this.applicationStartup);
		// 预初始化spring上下文
		prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
		// 刷新Spring容器
		refreshContext(context);
		afterRefresh(context, applicationArguments);
		// 打印启动时间
		Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
		if (this.logStartupInfo) {
    
    
			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
		}
		// 发布ApplicationStartedEvent事件和AvailabilityChangeEvent事件
		listeners.started(context, timeTakenToStartup);
		// 获取Spring容器中的ApplicationRunner/CommandLineRunner类型的Bean,并执行run方法
		callRunners(context, applicationArguments);
	}
	catch (Throwable ex) {
    
    
		if (ex instanceof AbandonedRunException) {
    
    
			throw ex;
		}
		// 发布ApplicationFailedEvent事件
		handleRunFailure(context, ex, listeners);
		throw new IllegalStateException(ex);
	}
	try {
    
    
		if (context.isRunning()) {
    
    
			Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
			// 发布ApplicationReadyEvent事件和AvailabilityChangeEvent事件
			listeners.ready(context, timeTakenToReady);
		}
	}
	catch (Throwable ex) {
    
    
		if (ex instanceof AbandonedRunException) {
    
    
			throw ex;
		}
		// 发布ApplicationFailedEvent事件
		handleRunFailure(context, ex, null);
		throw new IllegalStateException(ex);
	}
	return context;
}

DefaultBootstrapContext の初期化

createBootstrapContext メソッドにステップインします。

ここに画像の説明を挿入

ヘッドレス モードを有効にする

ヘッドレス モードは、ディスプレイ画面、キーボード、またはマウスがないシステム構成です。

configureHeadlessProperty メソッドにステップ インします。

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

ヘッドレス モードを有効にするには、setProperty メソッドを使用して、対応するシステム プロパティを設定する必要があります。

System.setProperty(“java.awt.headless”,true)

同じプログラムでヘッドレス環境と従来の環境を使用する場合は、次のコマンド ラインを使用して実行できます。

java -Djava.awt.headless=true

リスナーを取得して開始する

SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);

SpringApplicationRunListeners を取得するために、SpringBoot は、SpringApplicationRunListener インターフェースを実装する EventPublishingRunListener を提供します.Spring は、
このクラスを使用して、ApplicationListener を定義することによって監視できる ApplicationContextInitializedEvent イベントを発行します。

getRunListeners メソッドにステップインします:getSpringFactoriesInstancesメソッドを呼び出してリスナーを取得します. このメソッドは以前に m キャッシュに入れられたため、前述したので、ここでパラメーターに従って値を取得できます.

最後に、SpringApplicationRunListener インスタンスが返されます。

ここに画像の説明を挿入
それから戻って電話してください:

listeners.starting(bootstrapContext, this.mainApplicationClass);

開始メソッドにステップインします。

ここに画像の説明を挿入
doWithListeners メソッドにステップインします。

ここに画像の説明を挿入
まず、listenerAction が呼び出されます。 (listener) -> listener.starting(bootstrapContext)

開始メソッドにステップインします。

ここに画像の説明を挿入

multicastInitialEvent メソッドにステップ インします。

ここに画像の説明を挿入
refreshApplicationListeners メソッドへのステップイン:
これらの 7 つのリスナーは、以前にロードしたものです:
ここに画像の説明を挿入
Callthis.initialMulticaster::addApplicationListenerメソッド:
プロキシのターゲット (登録されている場合) を明示的に削除して、同じリスナーへの二重呼び出しを回避します。
applicationListeners のセット コレクションに追加します。
ここに画像の説明を挿入
実行後のリターン:

ここに画像の説明を挿入
multicastEvent メソッドにステップ インします。

ここに画像の説明を挿入
invokeListener メソッドにステップインします。

ここに画像の説明を挿入
doInvokeListener

ここに画像の説明を挿入
listener.onApplicationEvent(イベント);

ここに画像の説明を挿入
onApplicationStartingEvent

ここに画像の説明を挿入
beforeInitialize

ここに画像の説明を挿入
最後にここに戻ります:

ここに画像の説明を挿入
ここに画像の説明を挿入

コマンドライン引数をカプセル化する

ここに画像の説明を挿入

コマンド ライン パラメータの設定:
ここに画像の説明を挿入

DefaultApplicationArguments施工方法:

public DefaultApplicationArguments(String... args) {
    
    
	Assert.notNull(args, "Args must not be null");
	this.source = new Source(args);
	this.args = args;
}

環境を整える

環境変数 (オペレーティング システムの環境変数/JVM の環境変数) の読み取り、および構成ファイル情報の読み取り (リスナーに基づいて、EventPublishingRunListener を使用して ApplicationEnvironmentPreparedEvent イベントが発行されます。デフォルトでは、このイベントを処理するための EnvironmentPostProcessorApplicationListener があります。もちろん、Define ApplicationListener を使用してこのイベントを処理することもできます. ApplicationListener がこのイベントを受け取ると、application.properties ファイルと application.yml ファイルを解析し、環境に追加します。

ここに画像の説明を挿入

prepareEnvironment メソッドにステップインします。

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
			DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
    
    
		// 根据不同的web类型创建不同实现的Environment对象,读取:java环境变量和系统环境变量
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		// 将命令行参数读取环境变量中
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		// 将@PropertieSource的配置信息 放在第一位,它的优先级是最低的
		ConfigurationPropertySources.attach(environment);
		// 发布了ApplicationEnvironmentPreparedEvent 的监听器 读取了全局配置文件
		listeners.environmentPrepared(bootstrapContext, environment);
		DefaultPropertiesPropertySource.moveToEnd(environment);
		Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
				"Environment prefix cannot be set via properties.");
		// 将所有spring.main 开头的配置信息绑定到SpringApplication中
		bindToSpringApplication(environment);
		if (!this.isCustomEnvironment) {
    
    
			EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
			environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
		}
		// 更新PropertySources配置
		ConfigurationPropertySources.attach(environment);
		return environment;
	}

ここに画像の説明を挿入

さまざまな Web タイプに応じてさまざまな実装の環境オブジェクトを作成し、Java 環境変数とシステム環境変数を読み取ります

ConfigurableEnvironment environment = getOrCreateEnvironment();

ここに画像の説明を挿入

// 将命令行参数读取环境变量中
configureEnvironment(environment, applicationArguments.getSourceArgs());

ここに画像の説明を挿入

// 将@PropertieSource的配置信息 放在第一位,它的优先级是最低的
ConfigurationPropertySources.attach(environment);

ここに画像の説明を挿入

// 发布了ApplicationEnvironmentPreparedEvent的监听器,读取了全局配置文件
listeners.environmentPrepared(bootstrapContext, environment);

最後に onApplicationEnvironmentPreparedEvent メソッドを呼び出します。

ここに画像の説明を挿入

postProcessEnvironment メソッドにステップインします。

ここに画像の説明を挿入
processAndApply メソッドにステップ インします。

ここに画像の説明を挿入

applyToEnvironment メソッドにステップ インします。
ここに画像の説明を挿入

// 将所有spring.main 开头的配置信息绑定到SpringApplication中
bindToSpringApplication(environment);

ここに画像の説明を挿入

バナーを印刷する

// 打印Banner
Banner printedBanner = printBanner(environment);

printBanner メソッドにステップ インします。

ここに画像の説明を挿入
print メソッドにステップ インします。

ここに画像の説明を挿入
getBanner メソッドにステップ インします。

ここに画像の説明を挿入
getTextBanner メソッドにステップ インします。最初に spring.banner.location の値を取得します。そうでない場合は、デフォルトでルート パスになり、banner.txt ファイルを出力します。

ここに画像の説明を挿入

バナーを取得すると、次のように出力されます。

banner.printBanner(environment, sourceClass, out);

ここに画像の説明を挿入

このメソッドにステップ インし、バナーを出力します。

ここに画像の説明を挿入

コンテキスト コンテナーの作成

// 据webApplicationType创建不同的Spring上下文容器(有三种)
context = createApplicationContext();

ここに画像の説明を挿入

コンテキスト コンテナを事前に初期化する

prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);

prepareContext メソッドにステップ インします。

最初にすべての ApplicationContextInitializers を取得し、ループ内で initialize メソッドを呼び出します。

beanFactory を取得します。

Bean を確認してください。重複する Bean がある場合は、例外がスローされます。

スタートアップ クラスを Spring コンテナに登録します。

ここに画像の説明を挿入

Spring コンテナーをリフレッシュする

前の章の記事では、Bean の読み込み、インスタンス化、初期化、AOP、トランザクション、Tomcat の起動に焦点を当てています。

表示する列に移動できます。

「Javaコアテクノロジー」

印刷開始時間

Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
			if (this.logStartupInfo) {
    
    
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
			}

イベント後

// 发布ApplicationStartedEvent事件和AvailabilityChangeEvent事件
listeners.started(context, timeTakenToStartup);

最後に、イベントを公開するためにこのメソッドに来ました:

ここに画像の説明を挿入
最後に公開します。

ここに画像の説明を挿入

特定の run メソッドを実行する

// 获取Spring容器中的ApplicationRunner/CommandLineRunner类型的Bean,并执行run方法
callRunners(context, applicationArguments);

ApplicationRunner と CommandLineRunner の紹介

ここに画像の説明を挿入


続いて、ApplicationReadyEvent イベントと AvailabilityChangeEvent イベントを発行し、例外を処理します。

おすすめ

転載: blog.csdn.net/CSDN_SAVIOR/article/details/129019377