記事ディレクトリ
前回の記事「【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 の起動に焦点を当てています。
表示する列に移動できます。
印刷開始時間
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 イベントを発行し、例外を処理します。