Spring Boot起動フロー分析
ことばを引く
15年前からspring bootで開発されていましたが、ずっと使うだけで、spring bootがどういう原理で働いているのかを深く理解していませんでした。恥ずかしいです。今日はspring bootからスタートして、spring bootの仕事原理を詳しく調べましょう。
どうしてspring bootを使いますか?
一つのものや道具を使う前に、私たちはいつも自分に聞きます。なぜ使うのですか?彼を使ったら私に何かいいところがありますか?
*最大の利点は、spring bootがjava**の約束に従って配置**より大きいということです。大量の配置ファイルに直面しなくてもいいです。spring bootはあなたが使っているカバンに基づいて、どのような配置を提供するかを決めます。
*サーバーはjarカバンの形でプロジェクトに埋め込まれています。マイクロサービスが飛び交う場合、spring bootは生まれつきマイクロサービスアーキテクチャに適しています。配置が便利です。
*devtoolsを提供してからコードを変更すると再起動して歴史になる必要があります。
長所があれば必ず欠点があります。短所は長所と短所から来ています。
*開発者が不透明であるため、ソースを見ないとJ DBCロードや事務管理などの方法が分かりません。
*自動配置の後、カスタム設定はjavaConfigを符号化する必要があります。これらの構成クラスのapiを知る必要があります。
*バージョンの反復が速すぎて、古いバージョンの変更が多すぎて、例えば1.3.5前のspringBootTestと1.4.0後のspringBootTestが互換性がない。
適切なアーキテクチャだけが最高のアーキテクチャです。もしspring bootのこれらの欠点を受け入れることができれば、spring bootは確かに開発効率を高めるいい選択です。
起動フロー
こんなにたくさん話して、本題に入ります。spring bootはどうやって起動して起動したのかを見てみましょう。
以下のコードはspring bootプロジェクト標準の起動方式で、注釈@Spring Bootationを使用して、mainメソッドでSprigAplicationのrunメソッドを呼び出すと完成できます。このrun法からspring bootの起動過程を見始めます。
これはすでにSpringApplicationをすべて実例化しましたが、Appliation Contact InitializerとAppliation Listenerをロードし終わった後にもう一つのステップがあります。スタートクラスの位置を見つけて、属性manApplication Classに設定します。
次に、
モニターを取得して起動します。
環境変数をロードします。この環境変数は、system environment、classipath environment、ユーザーが自分で加えたappication.propertiesを含みます。
Apple Comptextを作成します。
締め括りをつける
spring boot初期化の内容はまだ多いですが、まとめたら4時です。
*SprigAplicationの例を作成し、環境を判定します。ウェブ環境ですか?それとも普通環境ですか?すべての必要なInitializersとListenersをロードして、ここで約束より大きい理念を使って自動配置のベールを開けました。
*環境変数をロードし、環境変数には、system environment、classipath environment、appication environment(つまり、私たちがカスタマイズしたappication.propertiesプロファイル)が含まれます。
*SprigAplication RunListenersを作成する
*Application Contectを作成し、組み立てcontextを設定し、ここで全てのbeanをスキャンし、最後にrefsh Contectの時にロード、注入します。最終的に組み立てられたcontextを属性としてSpringAppliation RunListenersに設定し、これでspring bootプロジェクトの起動が完了しました。
以上は小编でご绍介したSpring Bootの起动过程です。皆さんに何かお聞きしたいことがあれば、メッセージをください。小编はすぐにご返事します。ここでも私たちのサイトを応援してくれてありがとうございます。
15年前からspring bootで開発されていましたが、ずっと使うだけで、spring bootがどういう原理で働いているのかを深く理解していませんでした。恥ずかしいです。今日はspring bootからスタートして、spring bootの仕事原理を詳しく調べましょう。
どうしてspring bootを使いますか?
一つのものや道具を使う前に、私たちはいつも自分に聞きます。なぜ使うのですか?彼を使ったら私に何かいいところがありますか?
*最大の利点は、spring bootがjava**の約束に従って配置**より大きいということです。大量の配置ファイルに直面しなくてもいいです。spring bootはあなたが使っているカバンに基づいて、どのような配置を提供するかを決めます。
*サーバーはjarカバンの形でプロジェクトに埋め込まれています。マイクロサービスが飛び交う場合、spring bootは生まれつきマイクロサービスアーキテクチャに適しています。配置が便利です。
*devtoolsを提供してからコードを変更すると再起動して歴史になる必要があります。
長所があれば必ず欠点があります。短所は長所と短所から来ています。
*開発者が不透明であるため、ソースを見ないとJ DBCロードや事務管理などの方法が分かりません。
*自動配置の後、カスタム設定はjavaConfigを符号化する必要があります。これらの構成クラスのapiを知る必要があります。
*バージョンの反復が速すぎて、古いバージョンの変更が多すぎて、例えば1.3.5前のspringBootTestと1.4.0後のspringBootTestが互換性がない。
適切なアーキテクチャだけが最高のアーキテクチャです。もしspring bootのこれらの欠点を受け入れることができれば、spring bootは確かに開発効率を高めるいい選択です。
起動フロー
こんなにたくさん話して、本題に入ります。spring bootはどうやって起動して起動したのかを見てみましょう。
以下のコードはspring bootプロジェクト標準の起動方式で、注釈@Spring Bootationを使用して、mainメソッドでSprigAplicationのrunメソッドを呼び出すと完成できます。このrun法からspring bootの起動過程を見始めます。
@SpringBootApplication
public class Application {
public static void main(String[] args){
SpringApplication.run(Application.class,args);
}
}
runメソッドに入ると、最終的にはnew SprigAplication(sources).run(args);new SprigAplication(sources).run(args);この方法は、springBootの起動は二つの部分に分けられ、第一部分:SprigAplicationの実用化が見られます。第二部分:この例を呼び出して、run方法を実行する。まずこのSpringApplicationの実用化過程を見てみます。
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
// webEnvironment
this.webEnvironment = deduceWebEnvironment();
// ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// ApplicationListener
setListeners((Collection)
getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
肝心な点は二つのセット方法で**します。setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class))** **setListeners((Collection)
getSpringFactoriesInstances(ApplicationListener.class))**
この二つの方法は同じです。具体例を選んで、Appplication Contect Initializerに話してください。
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
//
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
// loadFactoryNames ApplicationContextInitializer
Set<String> names = new LinkedHashSet<String>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// ApplicationContextInitializer
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
//
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
自動配置の鍵はこのget SprigFactoresInstance方法です。正確にはこの方法のloadFactoryNames方法です。浪さんはこのloadFactoryNames方法が何をしているかを見てみます。自動配置はどうなりますか?
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
Enumeration<URL> urls = classLoader != null?classLoader.getResources("META-INF/spring.factories"):ClassLoader.getSystemResources("META-INF/spring.factories");
ArrayList result = new ArrayList();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
String factoryClassNames = properties.getProperty(factoryClassName);
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
return result;
} catch (IOException var8) {
throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
}
}
この方法を見て一つのことをしました。META-INF/spring.factoresというルートからすべての「url」を取り出してきました。このルートの下で何かを見に行きます。
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
springはあなたがロードしたjarカバンの中から必要なApple Contection Contect Initializerを見つけて動的に配置しています。特定のmavenパッケージを使えば、初期化の時にこのカバンのMETA-INF/spring.factoresの必要な種類を探しています。設定は不要です。これはすでにSpringApplicationをすべて実例化しましたが、Appliation Contact InitializerとAppliation Listenerをロードし終わった後にもう一つのステップがあります。スタートクラスの位置を見つけて、属性manApplication Classに設定します。
次に、
new SpringApplication(sources).run(args)
方法に戻って、run方法がどうなっているかを見てみましょう。
public ConfigurableApplicationContext run(String... args) {
// ,
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
// SpringApplicationRunListener
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
// console
Banner printedBanner = printBanner(environment);
// boss->ApplicationContext
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
この方法の中で一番重要なことは三つです。モニターを取得して起動します。
環境変数をロードします。この環境変数は、system environment、classipath environment、ユーザーが自分で加えたappication.propertiesを含みます。
Apple Comptextを作成します。
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the sources
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
listeners.contextLoaded(context);
}
前の2時は何も言いませんでした。第3回を重点的に話して、Application Contectを作ります。application Comptextを作成して、またいくつかの部に分けられます。実例化aplication Contect、preparext、refshComptext。具体例化appection Comptextは、前に述べたwebEnvironmentという属性によって、webContect類AnnotationConfigEmbodWebAppliation Computextを使って反射によって実行されます。appicationComptextの実装が完了したらprepare Comptextのプロセスに入ります。このprepare Contectの方法は、ロードする前に準備したenvironmentがcontextに入ります。そしてbeanNameGeneratorとreource Loaderがあれば、事前にbeanを作成してappration Contextにロードします。前の実装のすべてのinitializersを初期化します。すべてのbeanはここでbeanのスキャンとローディングを行います。今回の話は起動プロセスですので、詳しくは説明しません。最後に作成したappicationContectをlistenerに設定し、prepare Contectプロセスは終了しました。最後にrefreshContectです。これはspringのbeanロード過程と一致しています。beanの注入、beanFactory、postProcess BenFactoryなど、詳しくはspring beanのライフサイクルを見に行きます。締め括りをつける
spring boot初期化の内容はまだ多いですが、まとめたら4時です。
*SprigAplicationの例を作成し、環境を判定します。ウェブ環境ですか?それとも普通環境ですか?すべての必要なInitializersとListenersをロードして、ここで約束より大きい理念を使って自動配置のベールを開けました。
*環境変数をロードし、環境変数には、system environment、classipath environment、appication environment(つまり、私たちがカスタマイズしたappication.propertiesプロファイル)が含まれます。
*SprigAplication RunListenersを作成する
*Application Contectを作成し、組み立てcontextを設定し、ここで全てのbeanをスキャンし、最後にrefsh Contectの時にロード、注入します。最終的に組み立てられたcontextを属性としてSpringAppliation RunListenersに設定し、これでspring bootプロジェクトの起動が完了しました。
以上は小编でご绍介したSpring Bootの起动过程です。皆さんに何かお聞きしたいことがあれば、メッセージをください。小编はすぐにご返事します。ここでも私たちのサイトを応援してくれてありがとうございます。