実行可能アーカイブのパッケージ化

プラグインは、アプリケーションのすべての依存関係を含む実行可能アーカイブ(jar ファイルおよび war ファイル)を作成し、java -jar で実行できます。

実行可能な jar のパッケージ化

bootJar タスクを使用して、実行可能 jar を構築できます。タスクは、java プラグインが適用されるときに自動的に作成され、BootJar (Javadoc) のインスタンスです。assemble タスクは bootJar タスクに依存するように自動的に構成されるため、assemble (または build)を実行すると bootJar タスクも実行されます。

実行可能な war のパッケージ化

bootWar タスクを使用して、実行可能な war を構築できます。タスクは、war プラグインが適用されるときに自動的に作成され、BootWar (Javadoc) のインスタンスです。assemble タスクは bootWar タスクに依存するように自動的に構成されるため、assemble (または build)を実行すると bootWar タスクも実行されます。

実行可能およびデプロイ可能な war のパッケージ化

war ファイルは、java -jar を使用して実行し、外部コンテナーにデプロイできるようにパッケージ化できます。これを行うには、providedRuntime 構成に埋め込みサーブレットコンテナーの依存関係を追加する必要があります。例:

  • Groovy

  • Kotlin

dependencies {
	implementation('org.springframework.boot:spring-boot-starter-web')
	providedRuntime('org.springframework.boot:spring-boot-starter-tomcat')
}
dependencies {
	implementation("org.springframework.boot:spring-boot-starter-web")
	providedRuntime("org.springframework.boot:spring-boot-starter-tomcat")
}

これにより、外部コンテナーのクラスと競合しない war ファイルの WEB-INF/lib-provided ディレクトリに確実にパッケージ化されます。

providedRuntime は、Gradle の compileOnly 構成よりも優先されます。他の制限の中でも、compileOnly の依存関係はテストクラスパスにないため、Web ベースの統合テストは失敗します。

実行可能アーカイブとプレーンアーカイブのパッケージ化

デフォルトでは、bootJar または bootWar タスクが構成されている場合、jar または war タスクは、アーカイブ分類子の規則として plain を使用するように構成されています。これにより、bootJar と jarbootWar と war の出力場所が異なり、実行可能アーカイブとプレーンアーカイブの両方を同時に構築できます。

プレーンアーカイブではなく実行可能アーカイブで分類子を使用する場合は、jar および bootJar タスクの次の例に示すように分類子を構成します。

  • Groovy

  • Kotlin

tasks.named("bootJar") {
	archiveClassifier = 'boot'
}

tasks.named("jar") {
	archiveClassifier = ''
}
tasks.named<BootJar>("bootJar") {
	archiveClassifier.set("boot")
}

tasks.named<Jar>("jar") {
	archiveClassifier.set("")
}

または、プレーンアーカイブをまったく作成しない場合は、次の jar タスクの例に示すように、そのタスクを無効にします。

  • Groovy

  • Kotlin

tasks.named("jar") {
	enabled = false
}
tasks.named<Jar>("jar") {
	enabled = false
}
ネイティブイメージを作成するときは、jar タスクを無効にしないでください。詳細については、#33238 [GitHub] (英語) を参照してください。

実行可能アーカイブパッケージの構成

BootJar (Javadoc) および BootWar (Javadoc) タスクは、それぞれ Gradle の Jar および War タスクのサブクラスです。その結果、jar または war をパッケージ化するときに使用できるすべての標準構成オプションは、実行可能な jar または war をパッケージ化するときにも使用できます。実行可能な jar および war に固有の構成オプションも多数提供されています。

メインクラスの構成

デフォルトでは、実行可能アーカイブのメインクラスは、メインソースセットの出力で public static void main(String[]) メソッドを持つクラスを探すことによって自動的に構成されます。

メインクラスは、タスクの mainClass プロパティを使用して明示的に構成することもできます。

  • Groovy

  • Kotlin

tasks.named("bootJar") {
	mainClass = 'com.example.ExampleApplication'
}
tasks.named<BootJar>("bootJar") {
	mainClass.set("com.example.ExampleApplication")
}

または、Spring Boot DSL の mainClass プロパティを使用して、プロジェクト全体でメインクラス名を設定できます。

  • Groovy

  • Kotlin

springBoot {
	mainClass = 'com.example.ExampleApplication'
}
springBoot {
	mainClass.set("com.example.ExampleApplication")
}

application プラグイン (英語) が適用されている場合は、その mainClass プロパティを構成する必要があり、同じ目的で使用できます。

  • Groovy

  • Kotlin

application {
	mainClass = 'com.example.ExampleApplication'
}
application {
	mainClass.set("com.example.ExampleApplication")
}

最後に、タスクのマニフェストで Start-Class 属性を構成できます。

  • Groovy

  • Kotlin

tasks.named("bootJar") {
	manifest {
		attributes 'Start-Class': 'com.example.ExampleApplication'
	}
}
tasks.named<BootJar>("bootJar") {
	manifest {
		attributes("Start-Class" to "com.example.ExampleApplication")
	}
}
メインクラスが Kotlin で記述されている場合は、生成された Java クラスの名前を使用する必要があります。デフォルトでは、これは Kt サフィックスが追加された Kotlin クラスの名前です。例: ExampleApplication は ExampleApplicationKt になります。@JvmName を使用して別の名前が定義されている場合は、その名前を使用する必要があります。

開発専用の依存関係を含める

デフォルトでは、developmentOnly 構成で宣言されたすべての依存関係は、実行可能な jar または war から除外されます。

developmentOnly 構成で宣言された依存関係をアーカイブに含める場合は、次の bootWar タスクの例に示すように、そのタスクのクラスパスを構成に含めるように構成します。

  • Groovy

  • Kotlin

tasks.named("bootWar") {
	classpath configurations.developmentOnly
}
tasks.named<BootWar>("bootWar") {
	classpath(configurations["developmentOnly"])
}

解凍が必要なライブラリの構成

ほとんどのライブラリは、実行可能アーカイブにネストされている場合に直接使用できますが、特定のライブラリには問題がある場合があります。例: JRuby には、jruby-complete.jar が常にファイルシステムで直接利用可能であることを前提とする独自のネストされた jar サポートが含まれています。

問題のあるライブラリを処理するために、実行可能アーカイブの実行時に、特定のネストされた jar を一時ディレクトリに解凍するように実行可能アーカイブを構成できます。ライブラリは、ソース jar ファイルの絶対パスと一致する Ant スタイルのパターンを使用して解凍する必要があると識別できます。

  • Groovy

  • Kotlin

tasks.named("bootJar") {
	requiresUnpack '**/jruby-complete-*.jar'
}
tasks.named<BootJar>("bootJar") {
	requiresUnpack("**/jruby-complete-*.jar")
}

さらに制御するために、クロージャを使用することもできます。クロージャには FileTreeElement が渡され、開梱が必要かどうかを示す boolean を返す必要があります。

アーカイブを完全に実行可能にする

Spring Boot は、完全に実行可能なアーカイブのサポートを提供します。アーカイブは、アプリケーションの起動方法を知っているシェルスクリプトを先頭に追加することにより、完全に実行可能になります。Unix ライクなプラットフォームでは、この起動スクリプトにより、アーカイブを他の実行可能ファイルのように直接実行したり、サービスとしてインストールしたりできます。

現在、一部のツールはこの形式を受け入れないため、この手法を常に使用できるとは限りません。例: jar -xf は、完全に実行可能にされた jar または war の抽出にサイレントに失敗する場合があります。このオプションは、java -jar で実行したり、サーブレットコンテナーにデプロイしたりするのではなく、直接実行する場合にのみ有効にすることをお勧めします。

この機能を使用するには、起動スクリプトの組み込みを有効にする必要があります。

  • Groovy

  • Kotlin

tasks.named("bootJar") {
	launchScript()
}
tasks.named<BootJar>("bootJar") {
	launchScript()
}

これにより、Spring Boot のデフォルトの起動スクリプトがアーカイブに追加されます。デフォルトの起動スクリプトには、適切なデフォルト値を持ついくつかのプロパティが含まれています。値は、properties プロパティを使用してカスタマイズできます。

  • Groovy

  • Kotlin

tasks.named("bootJar") {
	launchScript {
		properties 'logFilename': 'example-app.log'
	}
}
tasks.named<BootJar>("bootJar") {
	launchScript {
		properties(mapOf("logFilename" to "example-app.log"))
	}
}

デフォルトの起動スクリプトがニーズを満たさない場合、script プロパティを使用してカスタム起動スクリプトを提供できます。

  • Groovy

  • Kotlin

tasks.named("bootJar") {
	launchScript {
		script = file('src/custom.script')
	}
}
tasks.named<BootJar>("bootJar") {
	launchScript {
		script = file("src/custom.script")
	}
}

PropertiesLauncher の使用

PropertiesLauncher を使用して実行可能な jar または war を起動するには、タスクのマニフェストを構成して Main-Class 属性を設定します。

  • Groovy

  • Kotlin

tasks.named("bootWar") {
	manifest {
		attributes 'Main-Class': 'org.springframework.boot.loader.launch.PropertiesLauncher'
	}
}
tasks.named<BootWar>("bootWar") {
	manifest {
		attributes("Main-Class" to "org.springframework.boot.loader.launch.PropertiesLauncher")
	}
}

階層化された Jar または War のパッケージ化

デフォルトでは、bootJar タスクは、アプリケーションのクラスと依存関係をそれぞれ BOOT-INF/classes と BOOT-INF/lib に含むアーカイブを構築します。同様に、bootWar は、WEB-INF/classes のアプリケーションのクラスと、WEB-INF/lib および WEB-INF/lib-provided の依存関係を含むアーカイブを構築します。jar のコンテンツから docker イメージを作成する必要がある場合は、これらのディレクトリをさらに分離して、個別のレイヤーに書き込むことができると便利です。

階層化された jar は、通常の Boot パッケージ jar と同じレイアウトを使用しますが、各レイヤーを説明する追加のメタデータファイルが含まれています。

デフォルトでは、次のレイヤーが定義されています。

  • バージョンに SNAPSHOT が含まれていないプロジェクト以外の依存関係の dependencies

  • jar ローダークラスの spring-boot-loader

  • バージョンに SNAPSHOT が含まれているプロジェクト以外の依存関係の snapshot-dependencies

  • プロジェクトの依存関係、アプリケーションクラス、リソース用の application

レイヤーの順序は、アプリケーションの一部が変更されたときに前のレイヤーがキャッシュされる可能性を決定するため、重要です。デフォルトの順序は dependenciesspring-boot-loadersnapshot-dependenciesapplication です。変更の可能性が最も低いコンテンツを最初に追加し、次に変更の可能性が高いレイヤーを追加する必要があります。

この機能を無効にするには、次の方法で無効にします。

  • Groovy

  • Kotlin

tasks.named("bootJar") {
	layered {
		enabled = false
	}
}
tasks.named<BootJar>("bootJar") {
	layered {
		enabled.set(false)
	}
}

階層化された jar または war が作成されると、spring-boot-jarmode-tools jar が依存関係としてアーカイブに追加されます。クラスパス上のこの jar を使用すると、特別なモードでアプリケーションを起動できます。これにより、ブートストラップコードで、アプリケーションとはまったく異なるもの(たとえば、レイヤーを抽出するもの)を実行できます。この依存関係を除外する場合は、次の方法で行うことができます。

  • Groovy

  • Kotlin

tasks.named("bootJar") {
	includeTools = false
}
tasks.named<BootJar>("bootJar") {
	includeTools.set(false)
}

カスタムレイヤー構成

アプリケーションによっては、レイヤーの作成方法を調整し、新しいレイヤーを追加したい場合があります。

これは、jar または war をレイヤーに分離する方法と、それらのレイヤーの順序を説明する構成を使用して実行できます。次の例は、上記のデフォルトの順序を明示的に定義する方法を示しています。

  • Groovy

  • Kotlin

tasks.named("bootJar") {
	layered {
		application {
			intoLayer("spring-boot-loader") {
				include "org/springframework/boot/loader/**"
			}
			intoLayer("application")
		}
		dependencies {
			intoLayer("application") {
				includeProjectDependencies()
			}
			intoLayer("snapshot-dependencies") {
				include "*:*:*SNAPSHOT"
			}
			intoLayer("dependencies")
		}
		layerOrder = ["dependencies", "spring-boot-loader", "snapshot-dependencies", "application"]
	}
}
tasks.named<BootJar>("bootJar") {
	layered {
		application {
			intoLayer("spring-boot-loader") {
				include("org/springframework/boot/loader/**")
			}
			intoLayer("application")
		}
		dependencies {
			intoLayer("application") {
				includeProjectDependencies()
			}
			intoLayer("snapshot-dependencies") {
				include("*:*:*SNAPSHOT")
			}
			intoLayer("dependencies")
		}
		layerOrder.set(listOf("dependencies", "spring-boot-loader", "snapshot-dependencies", "application"))
	}
}

layered DSL は、3 つの部分を使用して定義されます。

  • application クロージャは、アプリケーションクラスとリソースを階層化する方法を定義します。

  • dependencies クロージャーは、依存関係を階層化する方法を定義します。

  • layerOrder メソッドは、レイヤーが書き込まれる順序を定義します。

ネストされた intoLayer クロージャーは、application および dependencies セクション内で使用され、レイヤーのコンテンツを要求します。これらのクロージャーは、定義された順序で上から下に評価されます。以前の intoLayer クロージャーによって要求されていないコンテンツは、引き続き後続のコンテンツで検討できます。

intoLayer クロージャーは、ネストされた include および exclude 呼び出しを使用してコンテンツを要求します。application クロージャーは、包含 / 除外パラメーターに Ant スタイルのパスマッチングを使用します。dependencies セクションは group:artifact[:version] パターンを使用します。また、プロジェクトの依存関係を含めたり除外したりするために使用できる includeProjectDependencies() および excludeProjectDependencies() メソッドも提供します。

include 呼び出しが行われない場合、すべてのコンテンツ(以前のクロージャーによって要求されていない)が考慮されます。

exclude 呼び出しが行われない場合、除外は適用されません。

上記の例の dependencies クロージャを見ると、最初の intoLayer が application レイヤーのすべてのプロジェクト依存関係を要求していることがわかります。次の intoLayer は、snapshot-dependencies レイヤーのすべての SNAPSHOT 依存関係を要求します。3 番目の最後の intoLayer は、dependencies レイヤーに残っているもの(この場合、プロジェクトの依存関係または SNAPSHOT ではない依存関係)を要求します。

application クロージャーにも同様のルールがあります。最初に、spring-boot-loader レイヤーの org/springframework/boot/loader/** コンテンツを要求します。次に、application レイヤーの残りのクラスとリソースを要求します。

intoLayer クロージャーが追加される順序は、多くの場合、レイヤーが書き込まれる順序とは異なります。このため、layerOrder メソッドは常に呼び出され、intoLayer 呼び出しによって参照されるすべてのレイヤーをカバーする必要があります。