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に配置する必要があります。

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

上記の例は、0063myapp.jar/BOOT-INF/classesA.class を見つける方法を示しています。ネストされたjarからの B.class は、実際には myapp.jar の位置 3452にあり、C.class は位置 3980にあります。

この情報を使用して、外部jarの適切な部分をシークすることにより、特定のネストされたエントリをロードできます。アーカイブを解凍する必要はなく、すべてのエントリデータをメモリに読み込む必要もありません。

2.1. 標準Java「JarFile」との互換性

Spring Boot Loaderは、既存のコードおよびライブラリとの互換性を維持するよう努めています。 org.springframework.boot.loader.jar.JarFilejava.util.jar.JarFile から拡張されており、ドロップイン置換として機能するはずです。 getURL() メソッドは、java.net.JarURLConnection と互換性のある接続を開き、Javaの URLClassLoaderで使用できる URL を返します。

3. 実行可能ファイルの起動

org.springframework.boot.loader.Launcher クラスは、実行可能なjarのメインエントリポイントとして使用される特別なブートストラップクラスです。これは、jarファイルの実際の Main-Class であり、適切な URLClassLoader をセットアップし、最終的に main() メソッドを呼び出すために使用されます。

3つのランチャーサブクラス(JarLauncher, WarLauncherおよび PropertiesLauncher)があります。それらの目的は、ディレクトリ内のネストされたjarファイルまたはwarファイルからリソース(.class ファイルなど)をロードすることです(明示的にクラスパスにあるファイルとは対照的です)。 JarLauncher および WarLauncherの場合、ネストされたパスは固定されています。 JarLauncherBOOT-INF/lib/を検索し、WarLauncherWEB-INF/lib/WEB-INF/lib-provided/を検索します。さらに必要な場合は、これらの場所に追加のjarを追加できます。 PropertiesLauncher は、デフォルトでアプリケーションアーカイブの BOOT-INF/lib/ を検索します。 loader.properties (ディレクトリ、アーカイブ、またはアーカイブ内のディレクトリのコンマ区切りリスト)で LOADER_PATH または loader.path と呼ばれる環境変数を設定することにより、追加の場所を追加できます。

3.1. ランチャーマニフェスト

META-INF/MANIFEST.MFMain-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)で有効にできる特別な機能がいくつかあります。次の表で、これらのプロパティについて説明します。

キー目的

loader.path

lib,${HOME}/app/libなどのコンマ区切りのクラスパス。 javac コマンドラインの通常の -classpath のように、以前のエントリが優先されます。

loader.home

loader.pathの相対パスを解決するために使用されます。例: loader.path=libを指定すると、${loader.home}/lib はクラスパスの場所です(そのディレクトリ内のすべてのjarファイルとともに)。このプロパティは、次の例 /opt/app のように、loader.properties ファイルを見つけるためにも使用されます。デフォルトは ${user.dir}です。

loader.args

mainメソッドのデフォルト引数(スペースで区切られます)。

loader.main

起動するメインクラスの名前(例: com.app.Application)。

loader.config.name

プロパティファイルの名前(例: launcher)。デフォルトは loaderです。

loader.config.location

プロパティファイルへのパス(例: classpath:loader.properties)。デフォルトは loader.propertiesです。

loader.system

すべてのプロパティをシステムプロパティに追加する必要があることを示すブールフラグ。デフォルトは falseです。

環境変数またはマニフェストエントリとして指定する場合、次の名前を使用する必要があります。

キーマニフェストエントリ環境変数

loader.path

Loader-Path

LOADER_PATH

loader.home

Loader-Home

LOADER_HOME

loader.args

Loader-Args

LOADER_ARGS

loader.main

Start-Class

LOADER_MAIN

loader.config.location

Loader-Config-Location

LOADER_CONFIG_LOCATION

loader.system

Loader-System

LOADER_SYSTEM

ビルドプラグインは、fat jarがビルドされると、Main-Class 属性を Start-Class に自動的に移動します。それを使用する場合は、Main-Class 属性を使用して Start-Classを除外することにより、起動するクラスの名前を指定します。

PropertiesLauncherの操作には、次の規則が適用されます。

  • loader.propertiesloader.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 (ローカルディレクトリまたはアーカイブから実行する場合はネストされたディレクトリを意味します)になります。このため、追加の構成が提供されていない場合、PropertiesLauncherJarLauncher と同じように動作します。

  • loader.path を使用して loader.properties の場所を構成することはできません( loader.properties の検索に使用されるクラスパスは、PropertiesLauncher の起動時のJVMクラスパスです)。

  • プレースホルダーの置換は、システムおよび環境変数に加えて、使用前にすべての値のプロパティファイル自体から行われます。

  • プロパティの検索順序(複数の場所を調べるのが理にかなっている場合)は、環境変数、システムプロパティ、loader.properties、展開されたアーカイブマニフェスト、およびアーカイブマニフェストです。

5. 実行可能なJarの制限

Spring Boot Loaderパッケージアプリケーションを使用するときは、次の制限を考慮する必要があります。

  • Zipエントリの圧縮: ZipEntry.STORED メソッドを使用して、ネストされたjarの ZipEntry を保存する必要があります。これは、ネストされたjar内の個々のコンテンツを直接検索できるようにするために必要です。ネストされたjarファイル自体のコンテンツは、外部jarの他のエントリと同様に、圧縮することができます。

  • システムclassLoader:起動したアプリケーションは、クラスをロードするときに Thread.getContextClassLoader() を使用する必要があります(ほとんどのライブラリとフレームワークはデフォルトで使用します)。 ClassLoader.getSystemClassLoader() でネストされたjarクラスをロードしようとすると失敗します。 java.util.Logging は常にシステムクラスローダーを使用します。このため、異なるロギング実装を検討する必要があります。

6. 代替シングルJarソリューション

上記の制限によりSpring Bootローダーを使用できないことを意味する場合、以下の代替案を検討してください。

Unofficial Translation by spring.pleiades.io. See the original content.