最近、会社のオープンAPIプラットフォームを最適化する時間があります。 Jarパッケージを入力していたとき、私は突然、Spring Bootを使用するのに非常に熟練していることに気付きましたが、Spring Bootが作成したJARの開始原理を知りませんでした。それから私は今回瓶を解凍し、それを見ました。それは私が想像したものとは本当に違っていました。以下は、解凍された瓶の完全な分析です。
Spring Bootのアプリケーションは投稿されていません。よりシンプルなデモの構造は似ています。さらに、私が使用したスプリングブートのバージョンは1.4.1です。スプリングブートジャーのスタートアップを分析するためのインターネット上に別の記事があります。それは1.4未満である必要があり、スタートアップ方法も現在のバージョンとは大きく異なります。
MVNクリーンインストールの後、ターゲットディレクトリを見ると、次のように2つのJARパッケージがあります。
xxxx.jarxxx.jar.original
これは、通常の瓶を実行可能なJARパッケージに変えるSpring Bootプラグインメカニズムに起因し、XXX.JAR.ORIGINALはMavenによって生成されたJARパッケージです。これらは、次のように、公式Spring Webサイトの記事に関連して見つけることができます。
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#executable-jar
以下は、Spring Bootアプリケーションによって生成されるJARのディレクトリ構造の一部であり、そのほとんどは省略されており、重要な部分のみが表示されます。
.├。--inf│├│。。 ││││││││││││││││││││││││││││││││││└ │││││││││││。Swaggerconfig.class││││││││││││││││││││││││││││││なり─アクセントロール。 Guru.csss││││。││。├。├├├。。。 com.weibangong.open ├├。RaunchEdurlClassLoader$ 1.Class├。なり職人クラスローダー。 ExplodedArchive $ fileEntry.class│├│。。
アプリケーションで書いたクラスに加えて、このJARには別の組織パッケージもあります。 Spring Bootアプリケーションは、Spring Bootプラグインを使用してこのパッケージに入ります。これは、MVNライフサイクルのパッケージステージを強化するためです。スタートアッププロセスで重要な役割を果たすのはこのパッケージです。さらに、アプリケーションで必要なさまざまな依存関係が瓶に入力され、スプリングブートの追加パッケージが入力されます。オールインワンができるこの瓶は、fat.jarとも呼ばれます。ここでは、jarの名前を交換するために常にfat.jarを使用します。
現時点では、次のように、Meta-INFのManifest.mfファイルを引き続き調べます。
マニフェストバージョン:1.0Implementation-Title:open :: server :: openapiimplementation-version:1.0-snapshotarchiver-version:plexus archiverbuiltation-vendor-id:com.weibangong.opens-boot-bortion:1.4.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1. Inc.main-class:org.springframework.boot.loader.porpertieslauncherstart-class:com.weibangong.open.openapi.springbootwebapplicationspring-boot-classes:boot-inf/classes/spring-boot-lib:boot-inf/lib/created-by:apache-jdk:apache-jdk: 1.8.0_20Implementation-url:http://maven.apache.org/open-server-openapi
ここで指定されているメインクラスは、スタートアッププログラムの代わりに個別に入力されるパッケージ内のクラスファイルであり、Manifest.mfファイルには、アプリケーションのスタートアッププログラムを指定する個別のスタートクラスがあります。
最初に、主な方法は次のとおりです。
public static void main(string [] args)throws exception {propertiesLauncher launcher = new PropertiesLauncher(); args = launcher.getargs(args); Launcher.launch(args);}起動方法を確認してください。この方法は親クラスランチャーにあり、親クラスの起動方法は次のとおりです。
Protected void Launch(String [] args、String Mainclass、classloader classloader)スロー例外{thread.currentthread()。setContextClassLoaser(classLoader); this.createmainmethodrunner(mainclass、args、classloader).run(); }保護されたMainMethodRunner CreateMainMethodRunner(String MainClass、String [] args、classloader classloader){return new Mainmethodrunner(Mainclass、args); }起動方法は、最終的にMainMethodRunnerオブジェクトをインスタンス化して実行方法を実行するCreateMainMethodRunnerメソッドを呼び出します。次のように、MainMethodRunnerソースコードにアクセスします。
パッケージorg.springframework.boot.loader; import java.lang.refllect.method; public class mainmethodrunner {private final string mainclassname;プライベートファイナルストリング[] args; Public MainMethodRunner(String Mainclass、String [] args){this.mainClassName = MainClass; this.args = args == null?null :( string [])args.clone(); } public void run()throws Exception {class mainclass = thread.currentThread()。getContextClassLoader()。loadclass(this.mainClassName);メソッドmainmethod = mainclass.getDeclaredMethod( "main"、new class [] {string []。class}); mainmethod.invoke((object)null、new object [] {this.args}); }}実行方法をチェックすると、スプリングブートジャーを実行するのは非常に簡単で、分析は基本的に終了します。
5。メインプログラムのスタートアッププロセス
JARの開始プロセスについて話した後、Spring Bootアプリケーションのメインプログラムの起動と読み込みプロセスについて話しましょう。まず、Spring Bootアプリケーションの主な方法を見てみましょう。
パッケージcn.com.devh; Import org.springframework.boot.springApplication; Import org.springframework.boot.autoconfigure.springframework.cloud.client.discovery.enablediscoverient; Import; org.springframework.cloud.netflix.eureka.EnableTeureKaclient; Import org.springframework.cloud.netflix.feign.enablefeignclients;/*** Xiaxuanが17/8/8/25に作成しました。 */@springbootapplication@enablefeignclients@enabaleekaclientpublic class a1serviceapplication {public static void main(string [] args){springApplication.run(a1serviceapplication.class、args); }}次のように、SpringApplicationの実行方法に移動します。
/** *デフォルト設定を使用して *指定されたソースから{@link springApplication}を実行するために使用できる静的ヘルパー。 * @paramソースロードするソース * @param argsアプリケーション引数(通常はJavaメインメソッドから渡されます) } /** *デフォルト設定とユーザーが提供する引数を使用して、指定されたソースから{@link springApplication}を実行するために使用できる静的ヘルパー。 * @paramはソースを送信してロードします * @paramは、アプリケーションの引数(通常はJavaメインメソッドから渡されます)を引用します。 }ここでは、SpringApplicationのインスタンス化が重要です。SpringApplicationコンストラクターに行きます。
/***新しい{@link springApplication}インスタンスを作成します。アプリケーションのコンテキストは、指定されたソースから *豆をロードします({@link springApplicationクラスレベル} *詳細についてはドキュメントを参照してください。インスタンスは * {@link #run(string ...)}を呼び出す前にカスタマイズできます。ソース){Iniveryize(Sources); ApproachContextinitializer.class);DEDUCEWEBENVIRONMENT()初期化メソッドでは、次のように、現在Webアプリケーションで開始されているのか、通常の瓶で開始されているのかを決定します。
private boolean deducewebenvironment(){for(string classname:web_environment_classes){if(!classutils.ispresent(classname、null)){return false; }} trueを返します。 }web_environment_classesは次のとおりです。
private static final String [] web_environment_classes = {"javax.servlet.servlet"、 "org.springframework.web.context.configurablewebapplicationcontext"};それらのいずれかが存在しない限り、現在のアプリケーションは通常の瓶の形で開始されます。
次に、SetInitializersメソッドはすべてのApplicationContextInitializersを初期化します。
/** * spring * {@link applicationContext}に適用される{@link applicationContextInitializer}を設定します。 * @Param InitialIzers Initializersを設定する */ public void setInitializers(collection <?extends applicationContextinitializer <? this.initializers.addall(initializers); } setListeners((collection)getSpringFactoriesInstances(applicationListener.class))**このステップは、すべてのリスナーを初期化します。
前のspringApplication(ソース).run(args)に戻りましょう。実行方法を入力すると、コードは次のとおりです。
/** * Springアプリケーションを実行して、新しい * {@link ApplicationContext}を作成して更新します。 * @param argsアプリケーションの引数(通常はJavaメインメソッドから渡されます) stopwatch.start(); configureableapplicationContext context = null; configureheadlessproperty(); SpringApplicationRunListenersリスナー= getRunListeners(args); listens.started(); try {applicationArguments applicationArguments = new DefaultApplicationArguments(args); Context = createandrefreshContext(リスナー、ApplicationArguments); AfterRefresh(Context、ApplicationArguments);リスナー。フィニッシュ(コンテキスト、null); stopwatch.stop(); if(this.logstartupinfo){new StartupInfologger(this.mainApplicationClass).logstarted(getApplicationLog()、sopwatch); } return Context; } catch(throwable ex){handlerunfailure(context、リスナー、ex);新しいIllegalStateException(Ex); }}このステップは、コンテキスト作成のCreateAndRefreshContext(リスナー、ApplicationArguments)を実行します。
private configurableapplicationContext createandrefreshContext(springApplicationRunListenersリスナー、ApplicationArguments ApplicationArguments){configureableApplicationContextコンテキスト; //環境を作成して構成するconfigureableenvironment環境= getorcreateenvironment(); configureenvironment(環境、ApplicationArguments.getSourceargs());リスナー。EnvironmentPrepared(環境); if(iswebenvironment(環境)&&!this.webenvironment){環境= converttostandardenvironment(環境); } if(this.bannermode!= banner.mode.off){printbanner(環境); } // ApplicationContext Context = createApplicationContext()を作成、ロード、更新、および実行するContext.SetenVironment(環境); postprocessApplicationContext(context); ApplyInitializers(コンテキスト); listens.contextprepared(context); if(this.logstartupinfo){logstartupinfo(context.getParent()== null); logstartupprofileinfo(context); } // Boot固有のSingleton Beans Context.getBeanFactory()。registerSingleton( "SpringApplicationArguments"、ApplicationArguments); //ソースをロードしました<オブジェクト>ソース= getSources(); assert.notempty(ソース、「ソースは空にしてはならない」); load(context、sources.toarray(new object [sources.size()])); listens.contextloaded(context); //コンテキストの更新(コンテキスト); if(this.registershutdownhook){try {context.registershutdownhook(); } catch(AccessControlexception ex){//一部の環境では許可されていません。 }} return Context; } //環境を作成して構成するconfigureableenvironment環境= getorcreateenvironment(); configureenvironment(環境、ApplicationArguments.getSourceargs());このステップは、環境の構成とロードを実行します。
if(this.bannermode!= banner.mode.off){printbanner(環境); }このステップは、スプリングブートロゴを印刷します。変更する必要がある場合は、banner.txtとbanner.txtをリソースファイルに追加して、必要なパターンに変更します。
// ApplicationContext Context = createApplicationContext(); return(configureableApplicationContext)beanutils.instantiate(contextclass); createapplicationContext()を作成、ロード、更新、実行します
作成コンテキストには、実際に作成されたコンテナが含まれており、JettyまたはTomcatを選択するかどうかにかかわらず、EmbeddedServletContainerFactoryの作成など、応答クラスがインスタンス化されます。
if(this.registershutdownhook){try {context.registershutdownhook(); } catch(AccessControlexception ex){//一部の環境では許可されていません。 }}このステップは、現在のコンテキストを登録し、キルコマンドを受信したときにコンテナを破壊することです。
基本的に、スタートアップ分析は終了しましたが、非常に時間がかかる詳細がまだあります。これについては、その後のブログ投稿で説明しますが、それが今日のすべてです。
要約すると、スプリングブートジャーのスタートアッププロセスは基本的に次の手順です。
1. Mavenを正常にパッケージ化すると、Spring BootプラグインはMavenライフサイクルを展開し、Spring Boot関連パッケージをJARに含めます。このJARには、アプリケーションによって生成されたJARに加えて、スプリングブートスタートアッププログラムに関連するクラスファイルが含まれています。
2。スプリングブートジャーのわずかに低いバージョンのスタートアッププロセスを見たことがあります。当時、私は現在のスレッドにメインプログラムを実行する新しいスレッドがあることを覚えています。今では、反射を直接使用してメインプログラムを開始するように変更されています。
要約します
上記は、編集者が紹介したスプリングブートジャーの原則の分析です。それがあなたに役立つことを願っています。ご質問がある場合は、メッセージを残してください。編集者は時間内に返信します。 wulin.comのウェブサイトへのご支援ありがとうございます!