AWS Lambda

AWS [Amazon] アダプターは Spring Cloud Function アプリを受け取り、AWSLambda で実行できる形式に変換します。

一般的に、AWS Lambda で Spring アプリケーションを実行するには 2 つの方法があります。

  1. Spring Cloud Function 経由で AWS Lambda アダプターを使用して、以下に概説する関数アプローチを実装します。これは、Amazon SQS または Amazon MQ キュー、Apache Kafka ストリームからのメッセージの処理、Amazon S3 でのファイルアップロードへの反応など、単一責任 API およびイベントおよびメッセージングベースのシステムに適しています。

  2. サーバーレス Java コンテナープロジェクト [GitHub] (英語) を介して、AWS Lambda で Spring Boot Web アプリケーションを実行します。これは、既存の Spring アプリケーションを AWS Lambda に移行する場合や、複数の API エンドポイントを持つ高度な API を構築し、使い慣れた RestController アプローチを維持したい場合に適しています。このアプローチについては、Spring Boot Web 用のサーバーレス Java コンテナーで詳しく説明されています。

以下のガイドでは、AWS と AWS Lambda の基本的な知識があることを前提とし、Spring が提供する追加の価値に焦点を当てています。AWS Lambda の使用開始方法の詳細は、このドキュメントの範囲外です。詳細を知りたい場合は、基本的な AWS Lambda の概念 [Amazon] または完全な AWS 上の Java の概要 (英語) を参照してください。

入門

Spring Cloud Function フレームワークのゴールの 1 つは、単純な機能アプリケーションを特定の環境 (AWS Lambda など) と互換性を持たせるために必要なインフラストラクチャ要素を提供することです。

Spring のコンテキストでは、単純な機能アプリケーションには、SupplierFunction、または Consumer 型の Bean が含まれます。

例を見てみましょう:

@SpringBootApplication
public class FunctionConfiguration {

	public static void main(String[] args) {
		SpringApplication.run(FunctionConfiguration.class, args);
	}

	@Bean
	public Function<String, String> uppercase() {
		return value -> value.toUpperCase();
	}
}

関数 Bean が定義された完全な Spring Boot アプリケーションを確認できます。表面的には、これは単なる別の Spring Boot アプリです。ただし、プロジェクトに Spring Cloud Function AWS アダプターを追加すると、完全に有効な AWS Lambda アプリケーションになります。

<dependencies>
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-function-adapter-aws</artifactId>
 </dependency>
</dependencies>

その他のコードや構成は必要ありません。ビルドしてデプロイする準備が整ったサンプルプロジェクトを用意しました。公式の Spring Cloud 関数サンプルリポジトリから [GitHub] (英語) アクセスできます。

JAR ファイルを生成するには、mvn clean package を実行するだけです。適切な AWS デプロイ可能な JAR ファイルを生成するために、必要な maven プラグインはすべてすでに設定されています。(JAR レイアウトの詳細については、JAR レイアウトに関する注記を参照してください)。

AWS Lambda 関数ハンドラー

特定の HTTP ポート (80, 443) のリスナーを介して機能を公開する従来の Web アプリケーションとは対照的に、AWS Lambda 関数は、Lambda 関数ハンドラー [Amazon] と呼ばれる定義済みのエントリポイントで呼び出されます。

AWS Lambda との統合を効率化するには、組み込みの org.springframework.cloud.function.adapter.aws.FunctionInvoker ハンドラーを使用することをお勧めします。このハンドラーは、多機能ルーティング、AWS 固有の機能からの分離、すぐに使用できる POJO 直列化などの高度な機能を提供します。詳細については、AWS リクエストハンドラーおよび AWS 関数ルーティングのセクションを参照してください。

デプロイ

アプリケーションをビルドした後、AWS コンソール、AWS コマンドラインインターフェース (CLI)、または AWS サーバーレスアプリケーションモデル (AWS SAM) [Amazon] AWS クラウド開発キット (AWS CDK) [Amazon] AWS CloudFormation [Amazon] テラフォーム [Amazon] などの Infrastructure as Code (IaC) ツールを使用して、JAR ファイルを手動でデプロイできます。

AWS コンソールで Hello world Lambda 関数を作成するには

  1. Lambda コンソールの関数ページ [Amazon] を開きます。

  2. 関数の作成を選択します。

  3. 最初から作成者を選択します。

  4. 関数名に MySpringLambdaFunction と入力します。

  5. ランタイムには、Java 21 を選択します。

  6. 関数の作成を選択します。

コードをアップロードして関数をテストするには:

  1. 以前に作成した JAR ファイル (例: target/function-sample-aws-0.0.1-SNAPSHOT-aws.jar) をアップロードします。

  2. エントリハンドラーメソッド org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest を提供します。

  3. 「テスト」タブに移動し、「テスト」ボタンをクリックします。関数は、提供された JSON ペイロードを大文字で返します。

aws spring lambda edit
aws spring lambda test

Infrastructure as Code (IaC) ツールを使用して デプロイを自動化するには、公式の AWS ドキュメント [Amazon] を参照してください。

AWS リクエストハンドラー

開始セクションで説明したように、AWS Lambda 関数は、ラムダ関数ハンドラー [Amazon] と呼ばれる定義済みのエントリポイントで呼び出されます。最も単純な形式では、これは Java メソッド参照になります。上記の例では、com.my.package.FunctionConfiguration::uppercase になります。この構成は、提供された JAR でどの Java メソッドを呼び出すかを AWS Lambda に通知するために必要です。

Lambda 関数が呼び出されると、追加のリクエストペイロードとコンテキストオブジェクトがこのハンドラーメソッドに渡されます。リクエストペイロードは、関数をトリガーした AWS サービス (Amazon API Gateway、Amazon S3、Amazon SQS、Apache Kafka など) によって異なります。コンテキストオブジェクトは、Lambda 関数、呼び出し、環境に関する追加情報 (一意のリクエスト ID など) を提供します ( 公式ドキュメントの Java コンテキストも参照 [Amazon] )。

AWS は、aws-lambda-java-events および aws-lambda-java-core ライブラリを介してペイロードおよびコンテキストオブジェクトを処理するための定義済みハンドラーインターフェース (RequestHandler または RequestStreamHandler と呼ばれる) を提供します。

Spring Cloud Function はすでにこれらのインターフェースを実装しており、AWS Lambda の詳細から関数コードを完全に抽象化する org.springframework.cloud.function.adapter.aws.FunctionInvoker を提供しています。これにより、関数を実行するプラットフォームに応じてエントリポイントを切り替えるだけで済みます。

ただし、一部のユースケースでは、AWS 環境と深く統合する必要があります。例: 関数が Amazon S3 ファイルのアップロードによってトリガーされた場合、特定の Amazon S3 プロパティにアクセスする必要がある場合があります。または、Amazon SQS キューからアイテムを処理するときに部分的なバッチレスポンスを返す必要がある場合があります。その場合、汎用 org.springframework.cloud.function.adapter.aws.FunctionInvoker を活用できますが、関数コード内から専用の AWS オブジェクトを操作することになります。

@Bean
public Function<S3Event, String> processS3Event() {}

@Bean
public Function<SQSEvent, SQSBatchResponse> processSQSEvent() {}

型変換

組み込みの FunctionInvoker を活用するもう 1 つの利点は、Spring Cloud Function が生の入力ストリームと関数によって宣言された型の間の型変換を透過的に処理しようとすることです。

たとえば、関数のシグネチャーが Function<Foo, Bar> の場合、受信ストリームイベントを Foo のインスタンスに変換しようとします。これは、リクエスト本文がビジネスオブジェクトを表し、AWS の詳細に関連付けられていない、API によってトリガーされる Lambda 関数で特に役立ちます。

イベント型が不明または判別できない場合 (例: Function<?, ?>)、Spring Cloud Function は受信ストリームイベントを汎用 Map に変換しようとします。

生の入力

生の入力にアクセスしたい場合があります。この場合、関数シグネチャーを宣言して InputStream を受け入れるようにするだけです (例: Function<InputStream, ?>)。指定すると、Spring Cloud 関数は変換を試みず、生の入力を直接関数に渡します。

AWS 関数ルーティング

Spring Cloud Function のコア機能の 1 つはルーティングです。この機能により、他の内部メソッドに委譲する特別な Java メソッド ( ラムダ関数ハンドラー [Amazon] として動作) を 1 つ持つことができます。汎用 FunctionInvoker が入門セクションの uppercase 関数にリクエストを自動的にルーティングしたときに、この機能が実際に動作しているのをすでに確認しました。

デフォルトでは、アプリに型 Function などの @Bean が複数ある場合、Spring Cloud FunctionCatalog から抽出され、フレームワークは最初に Function、次に Consumer、最後に Supplier を検索するという検索順序に従ってデフォルトを見つけようとします。これらのデフォルトのルーティング機能が必要なのは、FunctionInvoker がどの関数をバインドするかを決定できないため、内部的に RoutingFunction がデフォルトになるためです。いくつかのメカニズムを使用して追加のルーティング指示を提供することをお勧めします (詳細についてはサンプル [GitHub] (英語) を参照してください)。

適切なルーティングメカニズムは、Spring Cloud Function プロジェクトを単一の Lambda 関数としてデプロイするか、複数の Lambda 関数としてデプロイするかの設定によって異なります。

単一機能と複数機能

同じ Spring Cloud Function プロジェクトに複数の Java メソッド (たとえば、uppercase と lowercase) を実装する場合は、静的ルーティング情報を持つ 2 つの個別の Lambda 関数をデプロイするか、実行時にどのメソッドを呼び出すかを決定する動的ルーティングメソッドを提供します。両方のアプローチを見てみましょう。

  1. 関数ごとに異なるスケーリング、構成、権限要件がある場合、2 つの個別の AWS Lambda 関数をデプロイすることは理にかなっています。例: 同じ Spring Cloud Function プロジェクトに 2 つの Java メソッド readObjectFromAmazonS3 と writeToAmazonDynamoDB を作成する場合、2 つの個別の Lambda 関数を作成することをお勧めします。これは、S3 または DynamoDB と通信するために異なる権限が必要であったり、負荷パターンやメモリ構成が大きく異なるためです。一般に、このアプローチは、Lambda イベントソースマッピング [Amazon] ごとに専用の構成があるため、ストリームまたはキューから読み取るメッセージングベースのアプリケーションにも推奨されます。

  2. 複数の Java メソッドが同じ権限セットを共有している場合や、まとまりのあるビジネス機能を提供している場合は、単一の Lambda 関数が有効なアプローチです。たとえば、CRUD ベースの Spring Cloud Function プロジェクトで、すべて同じ DynamoDB テーブルと通信し、同様の使用パターンを持つ createPetupdatePetreadPetdeletePet メソッドがあるとします。単一の Lambda 関数を使用すると、共有クラス (PetEntity) の デプロイのシンプルさ、まとまり、コード再利用が向上します。さらに、readPet の後に writePet が続くと、すでに実行中の Lambda 実行環境 [Amazon] がヒットする可能性が高くなるため、連続呼び出し間のコールドスタートを減らすことができます。ただし、より高度な API を構築する場合や、@RestController アプローチを活用する場合は、Spring Boot Web 用のサーバーレス Java コンテナーオプションも評価する必要があります。

最初のアプローチを好む場合は、2 つの別々の Spring Cloud Function プロジェクトを作成し、個別にデプロイすることもできます。これは、異なるチームが関数の保守とデプロイを担当している場合に役立ちます。ただし、その場合は、ヘルパーメソッドやエンティティクラスなどの横断的な関心事をそれらの間で共有する必要があります。一般に、従来の Web ベースのアプリケーションの場合と同じソフトウェアモジュール化の原則を機能プロジェクトに適用することをお勧めします。適切なアプローチを選択する方法の詳細については、サーバーレスマイクロサービスの設計アプローチの比較 [Amazon] を参照してください。

決定が下されたら、次のルーティングメカニズムを活用できます。

複数の Lambda 関数のルーティング

単一の Spring Cloud Function プロジェクト (JAR) を複数の Lambda 関数にデプロイすることに決めた場合は、呼び出す特定のメソッド ( uppercase や lowercase など) に関するヒントを提供する必要があります。ルーティング指示を提供するには、AWS Lambda 環境変数 [Amazon] を使用できます。

AWS では、環境変数の名前にドット . やハイフン - を使用することはできません。Spring Boot のサポートを利用し、ドットをアンダースコアに、ハイフンをキャメルケースに置き換えるだけで済みます。たとえば、spring.cloud.function.definition は spring_cloud_function_definition に、spring.cloud.function.routing-expression は spring_cloud_function_routingExpression になります。

2 つのメソッドを別々の AWS Lambda 関数にデプロイした単一の Spring Cloud プロジェクトの構成は次のようになります。

@SpringBootApplication
public class FunctionConfiguration {

	public static void main(String[] args) {
		SpringApplication.run(FunctionConfiguration.class, args);
	}

	@Bean
	public Function<String, String> uppercase() {
		return value -> value.toUpperCase();
	}

    @Bean
	public Function<String, String> lowercase() {
		return value -> value.toLowerCase();
	}
}
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
  MyUpperCaseLambda:
    Type: AWS::Serverless::Function
    Properties:
      Handler: org.springframework.cloud.function.adapter.aws.FunctionInvoker
      Runtime: java21
      MemorySize: 512
      CodeUri: target/function-sample-aws-0.0.1-SNAPSHOT-aws.jar
      Environment:
        Variables:
          spring_cloud_function_definition: uppercase

  MyLowerCaseLambda:
    Type: AWS::Serverless::Function
    Properties:
      Handler: org.springframework.cloud.function.adapter.aws.FunctionInvoker
      Runtime: java21
      MemorySize: 512
      CodeUri: target/function-sample-aws-0.0.1-SNAPSHOT-aws.jar
      Environment:
        Variables:
          spring_cloud_function_definition: lowercase

Lambda 関数ハンドラーを使用して、エントリメソッドを uppercase および lowercase に直接ポイントしないのはなぜかと疑問に思うかもしれません。Spring Cloud Function プロジェクトでは、AWS リクエストハンドラーで概説されているように、組み込みの FunctionInvoker を使用することをお勧めします。そのため、環境変数を介してルーティング定義を提供します。

単一の Lambda 関数内でのルーティング

複数の方法 (uppercase または lowercase) を使用して Spring Cloud Function プロジェクトを単一の Lambda 関数にデプロイすることに決めた場合は、より動的なルーティングアプローチが必要です。application.properties と環境変数はビルド時または デプロイ時に定義されるため、単一の関数シナリオでは使用できません。この場合は、Spring Cloud Function ルーティングセクションで概説されているように、MessagingRoutingCallback または Message Headers を活用できます。

詳細については、提供されているサンプル [GitHub] (英語) を参照してください。

パフォーマンスに関する考慮事項

サーバーレス関数の核となる特徴は、ゼロにスケールし、突然のトラフィックの急増に対処できることです。リクエストを処理するために、AWS Lambda は新しい実行環境 [Amazon] を起動します。これらの環境を初期化し、コードをダウンロードして、JVM とアプリケーションを起動する必要があります。これはコールドスタートとも呼ばれます。このコールドスタート時間を短縮するには、次のメカニズムを利用してパフォーマンスを最適化できます。

  1. AWS Lambda SnapStart を活用して、事前に初期化されたスナップショットから Lambda 関数を開始します。

  2. AWS Lambda Power Tuning を使用してメモリ構成を調整し、パフォーマンスとコストの最適なトレードオフを見つけます。

  3. ハンドラーコードの外部で SDK クライアントを定義するなどの AWS SDK ベストプラクティスに従うか、より高度なプライミング手法を活用します。

  4. 関数 Bean 登録 [GitHub] (英語) などの Spring の起動と初期化時間を短縮するために、追加の Spring メカニズムを実装します。

詳細については公式ガイダンス [Amazon] を参照してください。

GraalVM ネイティブイメージ

Spring Cloud Function は、AWS Lambda で実行される関数に対して GraalVM ネイティブイメージのサポートを提供します。GraalVM ネイティブイメージは従来の Java 仮想マシン (JVM) では実行されないため、ネイティブ Spring Cloud Function を AWS Lambda カスタムランタイムにデプロイする必要があります。最も顕著な違いは、JAR ファイルではなく、ネイティブイメージと起動手順を含むブートストラップファイルを zip パッケージにバンドルして提供することです。

lambda-custom-runtime.zip
  |-- bootstrap
  |-- function-sample-aws-native

ブートストラップファイル:

#!/bin/sh

cd ${LAMBDA_TASK_ROOT:-.}

./function-sample-aws-native

カスタムランタイム

Lambda は、安定した長期サポート (LTS) Java ランタイムバージョンの提供に重点を置いています。公式の Lambda ランタイムは、メンテナンスとセキュリティ更新の対象となるオペレーティングシステム、プログラミング言語、ソフトウェアライブラリの組み合わせに基づいて構築されています。例: Java の Lambda ランタイムは、Java 17 Corretto や Java 21 Corretto などの LTS バージョンをサポートしています。完全なリストは、こちら [Amazon] で確認できます。Java 22、Java 23、Java 24 などの非 LTS バージョンには、ランタイムは提供されていません。

他の言語バージョン、JVM、GraalVM ネイティブイメージを使用するには、Lambda でカスタムランタイムを作成 [Amazon] できます。カスタムランタイムを使用すると、アプリケーションコードを実行するための独自のランタイムを提供および構成できます。Spring Cloud Function は、これを簡単にするために必要なすべてのコンポーネントを提供します。

コードの観点から見ると、アプリケーションは他の Spring Cloud Function アプリケーションと変わらないはずです。必要なのは、Spring Boot アプリケーションを実行する ZIP/JAR のルートに bootstrap スクリプトを用意することだけです。AWS で関数を作成するときに、「カスタムランタイム」を選択します。次に、「ブートストラップ」ファイルの例を示します。

#!/bin/sh

cd ${LAMBDA_TASK_ROOT:-.}

java -Dspring.main.web-application-type=none -Dspring.jmx.enabled=false \
  -noverify -XX:TieredStopAtLevel=1 -Xss256K -XX:MaxMetaspaceSize=128M \
  -Djava.security.egd=file:/dev/./urandom \
  -cp .:`echo lib/*.jar | tr ' ' :` com.example.LambdaApplication

com.example.LambdaApplication は、関数 Bean を含むアプリケーションを表します。

AWS のハンドラー名を関数の名前に設定します。ここでも関数の構成を使用できます (例: uppercase|reverse)。ZIP/JAR を AWS にアップロードすると、関数はカスタムランタイムで実行されます。ZIP ファイルを適切に生成するために POM を構成する方法を確認できるサンプルプロジェクト [GitHub] (英語) も提供しています。

関数 Bean 定義スタイルは、カスタムランタイムでも機能し、@Bean スタイルよりも高速です。カスタムランタイムは、Java ラムダの関数 Bean 実装よりもはるかに高速に起動できます。これは、実行時にロードする必要のあるクラスの数に大きく依存します。Spring はここではあまり機能しないため、たとえば、関数でプリミティブ型のみを使用し、カスタム @PostConstruct 初期化子で作業を行わないことで、コールドスタート時間を短縮できます。

カスタムランタイムを使用した AWS 関数ルーティング

カスタムランタイム関数を使用する場合、ルーティングは同じように機能します。必要なのは、関数の名前をハンドラーとして使用するのと同じ方法で、functionRouter を AWS ハンドラーとして指定することだけです。

Lambda 関数をコンテナーイメージとしてデプロイする

JAR または ZIP ベースの デプロイとは異なり、イメージレジストリを介して Lambda 関数をコンテナーイメージとしてデプロイすることもできます。詳細については、公式の AWS Lambda ドキュメント [Amazon] を参照してください。

ここで説明した方法と同様の方法でコンテナーイメージをデプロイする場合は、関数の名前で環境変数 DEFAULT_HANDLER を設定することを忘れないことが重要です。

例: 以下に示す関数 Bean の場合、DEFAULT_HANDLER 値は readMessageFromSQS になります。

@Bean
public Consumer<Message<SQSMessageEvent>> readMessageFromSQS() {
	return incomingMessage -> {..}
}

また、spring_cloud_function_web_export_enabled も false に設定されていることを確認することも重要です。デフォルトでは true です。

JAR レイアウトに関する注記

Lambda では実行時に Spring Cloud Function Web または Stream アダプターは必要ないため、AWS に送信する JAR を作成する前に除外する必要がある場合があります。Lambda アプリケーションはシェーディングする必要がありますが、Spring Boot スタンドアロンアプリケーションはシェーディングしないため、2 つの別々の jar を使用して同じアプリを実行できます(サンプルのとおり)。サンプルアプリは、2 つの jar ファイルを作成します。1 つは Lambda にデプロイするための aws 分類子を使用し、もう 1 つは実行時に spring-cloud-function-web を含む 実行可能(シン)jar を作成します。Spring Cloud Function は、Start-Class 属性(親スターターを使用する場合は Spring Boot ツールによって追加されます)を使用して、JAR ファイルマニフェストから「メインクラス」を見つけようとします。マニフェストに Start-Class がない場合は、関数を AWS にデプロイするときに環境変数またはシステムプロパティ MAIN_CLASS を使用できます。

関数 Bean 定義を使用しておらず、Spring Boot の自動構成に依存しており、spring-boot-starter-parent に依存していない場合は、追加のトランスフォーマーを maven-shade-plugin 実行の一部として構成する必要があります。

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-shade-plugin</artifactId>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
			<version>3.4.2</version>
		</dependency>
	</dependencies>
	<executions>
		<execution>
			<goals>
			     <goal>shade</goal>
			</goals>
			<configuration>
				<createDependencyReducedPom>false</createDependencyReducedPom>
				<shadedArtifactAttached>true</shadedArtifactAttached>
				<shadedClassifierName>aws</shadedClassifierName>
				<transformers>
					<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
						<resource>META-INF/spring.handlers</resource>
					</transformer>
					<transformer implementation="org.springframework.boot.maven.PropertiesMergingResourceTransformer">
						<resource>META-INF/spring.factories</resource>
					</transformer>
					<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
						<resource>META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports</resource>
					</transformer>
					<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
						<resource>META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports</resource>
					</transformer>
					<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
						<resource>META-INF/spring.schemas</resource>
					</transformer>
					<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
						<resource>META-INF/spring.components</resource>
					</transformer>
				</transformers>
			</configuration>
		</execution>
	</executions>
</plugin>

ビルドファイルの設定

AWS Lambda で Spring Cloud Function アプリケーションを実行するには、Maven または Gradle プラグインを活用できます。

Maven

Maven のアダプタープラグインを使用するには、プラグインの依存関係を pom.xml ファイルに追加します。

<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-function-adapter-aws</artifactId>
	</dependency>
</dependencies>

JAR レイアウトに関する注記で指摘されているように、AWS Lambda にアップロードするには、シェーディングされた jar が必要です。そのために Maven Shade プラグイン [Apache] (英語) を使用できます。セットアップの例は上記にあります。

Spring Boot Maven プラグインを使用して、シン jar を生成できます。

<plugin>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-maven-plugin</artifactId>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot.experimental</groupId>
			<artifactId>spring-boot-thin-layout</artifactId>
			<version>${wrapper.version}</version>
		</dependency>
	</dependencies>
</plugin>

Maven を使用して AWSLambda に Spring Cloud Function アプリケーションをデプロイするためのサンプル pom.xml ファイル全体は ​ ここにあります [GitHub] (英語)

Gradle

Gradle のアダプタープラグインを使用するには、build.gradle ファイルに依存関係を追加します。

dependencies {
	compile("org.springframework.cloud:spring-cloud-function-adapter-aws:${version}")
}

JAR レイアウトに関する注記で指摘されているように、AWS Lambda にアップロードするには、シェーディングされた jar が必要です。そのために Gradle Shadow プラグイン (英語) を使用できます。

Spring Boot Gradle プラグインと Spring Boot シン Gradle プラグインを使用してシン jar を生成できます。

以下は完全な gradle ファイルです

plugins {
	id 'java'
	id 'org.springframework.boot' version '3.4.2'
	id 'io.spring.dependency-management' version '1.1.3'
	id 'com.github.johnrengelman.shadow' version '8.1.1'
	id 'maven-publish'
	id 'org.springframework.boot.experimental.thin-launcher' version "1.0.31.RELEASE"
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'

java {
	sourceCompatibility = '17'
}

repositories {
	mavenCentral()
	mavenLocal()
	maven { url 'https://repo.spring.io/milestone' }
}

ext {
	set('springCloudVersion', "2024.0.0")
}

assemble.dependsOn = [thinJar, shadowJar]

publishing {
	publications {
		maven(MavenPublication) {
			from components.java
			versionMapping {
				usage('java-api') {
					fromResolutionOf('runtimeClasspath')
				}
				usage('java-runtime') {
					fromResolutionResult()
				}
			}
		}
	}
}

shadowJar.mustRunAfter thinJar


import com.github.jengelman.gradle.plugins.shadow.transformers.*

shadowJar {
	archiveClassifier = 'aws'
	manifest {
    	inheritFrom(project.tasks.thinJar.manifest)
  	}
  	// Required for Spring
	mergeServiceFiles()
	append 'META-INF/spring.handlers'
	append 'META-INF/spring.schemas'
	append 'META-INF/spring.tooling'
	append 'META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports'
	append 'META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports'
	transform(PropertiesFileTransformer) {
		paths = ['META-INF/spring.factories']
		mergeStrategy = "append"
	}
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter'
	implementation 'org.springframework.cloud:spring-cloud-function-adapter-aws'
	implementation 'org.springframework.cloud:spring-cloud-function-context'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

dependencyManagement {
	imports {
		mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
	}
}

tasks.named('test') {
	useJUnitPlatform()
}

Gradle を使用して AWSLambda に Spring Cloud Function アプリケーションをデプロイするためのサンプル build.gradle ファイル全体は ​ ここにあります [GitHub] (英語)

Spring Boot Web 用のサーバーレス Java コンテナー

aws-serverless-java-container [GitHub] (英語) ライブラリを使用して、AWS Lambda で Spring Boot 3 アプリケーションを実行できます。これは、既存の Spring アプリケーションを AWS Lambda に移行する場合や、複数の API エンドポイントを持つ高度な API を構築し、使い慣れた RestController アプローチを維持したい場合に適しています。次のセクションでは、プロセスの概要を説明します。詳細については、公式のサンプルコード [GitHub] (英語) を参照してください。

  1. 既存の Spring Boot 3Web アプリにサーバーレス Java コンテナーライブラリをインポートする

    <dependency>
     <groupId>com.amazonaws.serverless</groupId>
     <artifactId>aws-serverless-java-container-springboot3</artifactId>
     <version>2.1.2</version>
    </dependency>
  2. エントリポイントとして機能する組み込みの Lambda 関数ハンドラーを使用する

    com.amazonaws.serverless.proxy.spring.SpringDelegatingLambdaContainerHandler

  3. MAIN_CLASS という環境変数を設定して、ジェネリクスハンドラーに元のアプリケーションのメインクラスがどこにあるか知らせます。通常、これは @SpringBootApplication でアノテーションが付けられたクラスです。

MAIN_CLAS = com.my.package.MySpringBootApplication

以下に、デプロイ構成の例を示します。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
  MySpringBootLambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: com.amazonaws.serverless.proxy.spring.SpringDelegatingLambdaContainerHandler
      Runtime: java21
      MemorySize: 1024
      CodeUri: target/lambda-spring-boot-app-0.0.1-SNAPSHOT.jar #Must be a shaded Jar
      Environment:
        Variables:
          MAIN_CLASS: com.amazonaws.serverless.sample.springboot3.Application #Class annotated with @SpringBootApplication

GraalVM ネイティブイメージを含むすべての例は、こちら [GitHub] (英語) でご覧いただけます。