spring-boot-loader モジュールにより、Spring Boot は実行可能な jar および war ファイルをサポートできます。Maven プラグインまたは Gradle プラグインを使用する場合、実行可能な jar は自動的に生成されるため、通常、それらがどのように機能するかの詳細を知る必要はありません。
別のビルドシステムから実行可能 jar を作成する必要がある場合、または基礎となるテクノロジに興味がある場合は、この付録で背景を説明します。
1. ネストされた JAR
Java は、ネストされた jar ファイル(つまり、jar 内に含まれる jar ファイル)をロードする標準的な方法を提供しません。これは、コマンドラインから展開せずに実行できる自己完結型アプリケーションを配布する必要がある場合に問題になる可能性があります。
この問題を解決するために、多くの開発者は「シェーディングされた」jar ファイルを使用します。シェーディングされた jar は、すべての jar からのすべてのクラスを単一の "uber jar" にパッケージ化します。シェーディングされた jar ファイルの問題は、どのライブラリが実際にアプリケーションに含まれているかを見にくくなることです。また、複数の jar で同じファイル名(ただし、異なるコンテンツ)が使用されている場合、問題が発生する可能性があります。Spring Boot は異なるアプローチを採用しており、実際に jar を直接ネストできます。
1.1. 実行可能な Jar ファイル構造
Spring Boot ローダー互換の jar ファイルは、次のように構成する必要があります。
example.jar
|
+-META-INF
| +-MANIFEST.MF
+-org
| +-springframework
| +-boot
| +-loader
| +-<spring boot loader classes>
+-BOOT-INF
+-classes
| +-mycompany
| +-project
| +-YourClasses.class
+-lib
+-dependency1.jar
+-dependency2.jar アプリケーションクラスは、ネストされた BOOT-INF/classes ディレクトリに配置する必要があります。依存関係は、ネストされた BOOT-INF/lib ディレクトリに配置する必要があります。
1.2. 実行可能な War ファイル構造
Spring Boot ローダー互換の war ファイルは、次のように構成する必要があります。
example.war
|
+-META-INF
| +-MANIFEST.MF
+-org
| +-springframework
| +-boot
| +-loader
| +-<spring boot loader classes>
+-WEB-INF
+-classes
| +-com
| +-mycompany
| +-project
| +-YourClasses.class
+-lib
| +-dependency1.jar
| +-dependency2.jar
+-lib-provided
+-servlet-api.jar
+-dependency3.jar 依存関係は、ネストされた WEB-INF/lib ディレクトリに配置する必要があります。組み込みの実行時に必要であるが、従来の Web コンテナーにデプロイする場合には不要な依存関係は、WEB-INF/lib-provided に配置する必要があります。
1.3. インデックスファイル
Spring Boot ローダー互換の jar および war アーカイブには、BOOT-INF/ ディレクトリに追加の索引ファイルを含めることができます。classpath.idx ファイルは jar と war の両方に提供でき、jar をクラスパスに追加する順序を提供します。layers.idx ファイルは jar にのみ使用でき、jar を論理レイヤーに分割して Docker/OCI イメージを作成できます。
インデックスファイルは YAML 互換の構文に準拠しているため、サードパーティのツールで簡単に解析できます。ただし、これらのファイルは内部的に YAML として解析されないため、使用するには以下に説明する形式で正確に記述する必要があります。
1.4. クラスパスインデックス
クラスパスインデックスファイルは、BOOT-INF/classpath.idx で提供できます。jar 名(ディレクトリを含む)のリストを、クラスパスに追加する順序で提供します。各行はダッシュスペース("-·")で始まる必要があり、名前は二重引用符で囲む必要があります。
例: 次の jar が与えられた場合:
example.jar
|
+-META-INF
| +-...
+-BOOT-INF
+-classes
| +...
+-lib
+-dependency1.jar
+-dependency2.jarインデックスファイルは次のようになります。
- "BOOT-INF/lib/dependency2.jar" - "BOOT-INF/lib/dependency1.jar"
1.5. レイヤーインデックス
レイヤーインデックスファイルは BOOT-INF/layers.idx で提供できます。レイヤーのリストと、レイヤー内に含まれる jar のパーツを提供します。レイヤーは、Docker/OCI イメージに追加する順序で書き込まれます。レイヤー名は、ダッシュスペース("-·")とコロン(":")サフィックスが前に付いた引用符付き文字列として記述されます。レイヤーコンテンツは、スペーススペースダッシュスペース("··-·")を前に付けた引用符付き文字列として記述されたファイルまたはディレクトリ名です。ディレクトリ名は / で終わりますが、ファイル名は終わりません。ディレクトリ名が使用されている場合、そのディレクトリ内のすべてのファイルが同じレイヤーにあることを意味します。
レイヤーインデックスの典型的な例は次のとおりです。
- "dependencies": - "BOOT-INF/lib/dependency1.jar" - "BOOT-INF/lib/dependency2.jar" - "application": - "BOOT-INF/classes/" - "META-INF/"
2. Spring Boot の "JarFile" クラス
ネストされた jar のロードをサポートするために使用されるコアクラスは org.springframework.boot.loader.jar.JarFile です。これにより、標準の jar ファイルまたはネストされた子 jar データから jar コンテンツをロードできます。最初にロードされるとき、各 JarEntry の場所は、次の例に示すように、外側の jar の物理ファイルオフセットにマップされます。
myapp.jar +-------------------+-------------------------+ | /BOOT-INF/classes | /BOOT-INF/lib/mylib.jar | |+-----------------+||+-----------+----------+| || A.class ||| B.class | C.class || |+-----------------+||+-----------+----------+| +-------------------+-------------------------+ ^ ^ ^ 0063 3452 3980
上記の例は、0063 の myapp.jar の /BOOT-INF/classes で A.class を見つける方法を示しています。ネストされた jar からの B.class は、実際には myapp.jar の位置 3452 にあり、C.class は位置 3980 にあります。
この情報を使用して、外部 jar の適切な部分をシークすることにより、特定のネストされたエントリをロードできます。アーカイブを解凍する必要はなく、すべてのエントリデータをメモリに読み込む必要もありません。
3. 実行可能ファイルの起動
org.springframework.boot.loader.Launcher クラスは、実行可能な jar のメインエントリポイントとして使用される特別なブートストラップクラスです。これは、jar ファイルの実際の Main-Class であり、適切な URLClassLoader をセットアップし、最終的に main() メソッドを呼び出すために使用されます。
3 つのランチャーサブクラス(JarLauncher、WarLauncher、PropertiesLauncher)があります。それらの目的は、ネストされた jar ファイルまたはディレクトリ内の war ファイル(クラスパスに明示的にあるものではなく)からリソース(.class ファイルなど)をロードすることです。JarLauncher および WarLauncher の場合、ネストされたパスは固定されています。JarLauncher は BOOT-INF/lib/ に見え、WarLauncher は WEB-INF/lib/ と WEB-INF/lib-provided/ に見えます。さらに必要な場合は、これらの場所に jar を追加できます。PropertiesLauncher は、デフォルトでアプリケーションアーカイブの BOOT-INF/lib/ を検索します。loader.properties (ディレクトリ、アーカイブ、アーカイブ内のディレクトリのコンマ区切りのリスト)で LOADER_PATH または loader.path と呼ばれる環境変数を設定することにより、場所を追加できます。
3.1. ランチャーマニフェスト
META-INF/MANIFEST.MF の Main-Class 属性として適切な Launcher を指定する必要があります。起動する実際のクラス(つまり、main メソッドを含むクラス)は、Start-Class 属性で指定する必要があります。
次の例は、実行可能な jar ファイルの一般的な MANIFEST.MF を示しています。
Main-Class: org.springframework.boot.loader.JarLauncher Start-Class: com.mycompany.project.MyApplication
war ファイルの場合、次のようになります。
Main-Class: org.springframework.boot.loader.WarLauncher Start-Class: com.mycompany.project.MyApplication
マニフェストファイルで Class-Path エントリを指定する必要はありません。クラスパスは、ネストされた jar から推定されます。 |
4. PropertiesLauncher の機能
PropertiesLauncher には、外部プロパティ(システムプロパティ、環境変数、マニフェストエントリ、loader.properties)で有効にできる特別な機能がいくつかあります。次の表で、これらのプロパティについて説明します。
| キー | 目的 |
|---|---|
|
|
|
|
| main メソッドのデフォルト引数(スペースで区切られます)。 |
| 起動するメインクラスの名前(例: |
| プロパティファイルの名前(例: |
| プロパティファイルへのパス(例: |
| すべてのプロパティをシステムプロパティに追加する必要があることを示すブールフラグ。デフォルトは |
環境変数またはマニフェストエントリとして指定する場合、次の名前を使用する必要があります。
| キー | マニフェストエントリ | 環境変数 |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ビルドプラグインは、fat jar がビルドされると、Main-Class 属性を Start-Class に自動的に移動します。それを使用する場合は、Main-Class 属性を使用して Start-Class を除外することにより、起動するクラスの名前を指定します。 |
PropertiesLauncher の操作には、次の規則が適用されます。
loader.propertiesはloader.homeで検索され、次にクラスパスのルートで検索され、次にclasspath:/BOOT-INF/classesで検索されます。その名前のファイルが存在する最初の場所が使用されます。loader.homeは、loader.config.locationが指定されていない場合のみ、追加のプロパティファイルのディレクトリの場所です(デフォルトを上書きします)。loader.pathには、ディレクトリ(jar および zip ファイルを再帰的にスキャンする)、アーカイブパス、jar ファイルをスキャンするアーカイブ内のディレクトリ(たとえばdependencies.jar!/lib)、またはワイルドカードパターン(デフォルトの JVM 動作の場合)を含めることができます。アーカイブパスは、loader.homeまたはjar:file:プレフィックスを持つファイルシステム内の任意の場所からの相対パスにすることができます。loader.path(空の場合)は、デフォルトでBOOT-INF/lib(ローカルディレクトリまたはアーカイブから実行する場合はネストされたディレクトリを意味します)になります。このため、追加の構成が提供されていない場合、PropertiesLauncherはJarLauncherと同じように動作します。loader.pathを使用してloader.propertiesの場所を構成することはできません(loader.propertiesの検索に使用されるクラスパスは、PropertiesLauncherの起動時の JVM クラスパスです)。プレースホルダーの置換は、システムおよび環境変数に加えて、使用前にすべての値のプロパティファイル自体から行われます。
プロパティの検索順序(複数の場所を調べるのが理にかなっている場合)は、環境変数、システムプロパティ、
loader.properties、展開されたアーカイブマニフェスト、アーカイブマニフェストです。
5. 実行可能な Jar の制限
Spring Boot Loader パッケージアプリケーションを使用するときは、次の制限を考慮する必要があります。
Zip エントリ圧縮: ネストされた jar の
ZipEntryは、ZipEntry.STOREDメソッドを使用して保存する必要があります。これは、ネストされた jar 内の個々のコンテンツを直接検索できるようにするために必要です。ネストされた jar ファイル自体のコンテンツは、外部 jar の他のエントリと同様に、圧縮することができます。
システム classLoader: 起動されたアプリケーションは、クラスをロードするときに
Thread.getContextClassLoader()を使用する必要があります(ほとんどのライブラリとフレームワークはデフォルトでそうします)。ClassLoader.getSystemClassLoader()でネストされた jar クラスをロードしようとすると失敗します。java.util.Loggingは常にシステムクラスローダーを使用します。このため、異なるロギング実装を検討する必要があります。