AWS LambdaでJavaのフレームワークを使うには！？

### TL;DR

AWS LambdaでJavaのフレームワーク、たとえばSpringBootなどを使いたいって思ったことありませんか？

結論としては、AWS Lambdaの上に、[aws-serverless-java-container](https://github.com/awslabs/aws-serverless-java-container)フレームワークというプロキシフレームワークを入れれば比較的簡単に実現可能です。

今日は、そのあたりを、このAWSブログを軽く意訳しつつ書いていきたいと思います。

[AWS Open Source Blog Running APIs Written in Java on AWS Lambda](https://aws.amazon.com/jp/blogs/opensource/java-apis-aws-lambda/)

### 背景

Java開発者は、SpringやSpring BootからJersey、Sparkといった慣れ親しんだフレームワークで開発していることが多いのではないでしょうか。

これらのフレームワークは、Tomcatなどのサーブレットコンテナを用いて、ビルドされたWarやJarをデプロイするか、アプリケーションを内包した実行可能なJarとして利用することができます。


AWSのサーバーレスでは、AWS LambdaとAmazon API GatewayでWEBのバックエンドが構築できますが、Lambdaがコンピュートを担い、API GatewayがRESTの管理を担います。

この記事では、Lambdaで使える、[aws-serverless-java-container](https://github.com/awslabs/aws-serverless-java-container)フレームワークをご紹介します。


### 仕組み

簡単に言うと、[aws-serverless-java-container](https://github.com/awslabs/aws-serverless-java-container)は、Spring、Spring Boot、Jersey、Sparkなどのフレームワークで作られたアプリケーションを、簡単に、最小限のコード変更でAWS Lambda内で実行できるようにするものです。

![フレームワーク間のプロキシ](https://d2908q01vomqb2.cloudfront.net/ca3512f4dfa95a03169c5a670a4c91a19b3077b4/2018/02/28/serverless-java-container-process-1-1024x472.png "https://aws.amazon.com/jp/blogs/opensource/java-apis-aws-lambda/より")


[aws-serverless-java-container](https://github.com/awslabs/aws-serverless-java-container)は、Lambdaランタイムと選択したフレームワーク間のプロキシとして機能し、サーブレットエンジンのふりをして、API GatewayからのEventをフレームワークが理解できるリクエストオブジェクトに変換し、アプリケーションからのレスポンスオブジェクトをAPI Gatewayの理解できる形式に変換します。


Spring Boot2をLambdaにのせて独自アプリを構築したい場合は、こちらに詳しい導入方法が紹介されています。
[Quick start Spring Boot2](https://github.com/awslabs/aws-serverless-java-container/wiki/Quick-start---Spring-Boot2) 



サンプルアプリダウンロード
---

awslabからaws-serverless-java-containerをcloneしてきましょう。この中に様々なJavaフレームワークのプロキシとサンプルコードが含まれています。

```bash
$ git clone https://github.com/awslabs/aws-serverless-java-container.git
```

独自アプリケーション用のプロキシはこちら

* [aws-serverless-java-container-jersey](https://github.com/awslabs/aws-serverless-java-container/tree/master/aws-serverless-java-container-jersey)
* [aws-serverless-java-container-spark](https://github.com/awslabs/aws-serverless-java-container/tree/master/aws-serverless-java-container-spark)
* [aws-serverless-java-container-spring](https://github.com/awslabs/aws-serverless-java-container/tree/master/aws-serverless-java-container-spring)
* [aws-serverless-java-container-springboot2](https://github.com/awslabs/aws-serverless-java-container/tree/master/aws-serverless-java-container-springboot2)
* [aws-serverless-java-container-struts2](https://github.com/awslabs/aws-serverless-java-container/tree/master/aws-serverless-java-container-struts2)

独自アプリを構築するにはこれらを使えばいいのですが、この記事では簡単のために、Spring Boot2のサンプルを利用したいと思います。


Spring Boot2のLambdaへの導入
---

[Spring Boot2 ペットショップサンプル](https://github.com/awslabs/aws-serverless-java-container/tree/master/samples/springboot2/pet-storee)

まず、以下の前提条件を満たしておきましょう。

* [Mavenインストール](https://maven.apache.org/)
* [AWS CLIインストール](https://aws.amazon.com/jp/cli/)

まず、mvnコマンドを使って、Javaアプリケーションをビルドしましょう。

```bash
$ cd aws-serverless-java-container/samples/springboot2/pet-store/
$ mvn package
```

mvnコマンドが成功すると、`serverless-spring-boot-example-1.0-SNAPSHOT.jar` が、`target`ディレクトリにできているはずです。

つぎに、AWS SAMを使って、Lambdaにデプロイするpackageを作ります。`<YOUR S3 BUCKET NAME>`には、適当なS3バケット名を指定しておきます。

```bash
$ aws cloudformation package --template-file sam.yaml --output-template-file output-sam.yaml --s3-bucket <YOUR S3 BUCKET NAME>
```

デプロイ用のパッケージができたら、次はいよいよLambdaへのデプロイです。このデプロイによってロジックを処理するAWS Lambdaと、HTTPSリクエストを受け取ってLambdaを呼び出すAPI Gatewayがデプロイされます。

```bash
$ aws cloudformation deploy --template-file output-sam.yaml --stack-name ServerlessSpringBootSample --capabilities CAPABILITY_IAM
```

デプロイが成功すると、以下のコマンドで実際に作られた、APIのエンドポイントを知ることができます。

```bash
$ aws cloudformation describe-stacks --stack-name ServerlessSpringBootSample
{
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:us-west-2:xxxxxxxx:stack/JerseySample/xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx", 
            "Description": "Example Pet Store API written with spark with the aws-serverless-java-container library", 
            "Tags": [], 
            "Outputs": [
                {
                    "Description": "URL for application", 
                    "OutputKey": "SpringBootPetStoreApi", 
                    "OutputValue": "https://xxxxxxx.execute-api.us-west-2.amazonaws.com/Prod/pets"
                }
            ], 
            "CreationTime": "2016-12-13T22:59:31.552Z", 
            "Capabilities": [
                "CAPABILITY_IAM"
            ], 
            "StackName": "JerseySample", 
            "NotificationARNs": [], 
            "StackStatus": "UPDATE_COMPLETE"
        }
    ]
}
```


`OutputValue`に指定されているAPIエンドポイントが、今回デプロイされ起動したAPIのURIになります。


動作確認してみましょう。


```bash
$ curl https://xxxxxxx.execute-api.us-west-2.amazonaws.com/Prod/pets
```

結果のJSONが返ってきたら成功です！


いかがだったでしょうか？サンプルアプリの導入がこんなに簡単にできました。

---

### 次のステップに進むには？

Spring Boot2は素晴らしいフレームワークで上の手順に従うことでLambdaにのせて実行させることは簡単にできるのですが、もっと小回りの効く、小さなフレームワークを導入したいといった場合`Spark`や`Micronaut`にも挑戦してみてください。

また、Lambdaの初回起動時のLatencyが気になるワークロードについてはOracle社が提供しているGraalVMを利用したNative実行も可能です。

MicronautとGraalVMを使ったNative化のサンプルはこちら
[Micronaut X GraalVMサンプルペットショップ](https://github.com/awslabs/aws-serverless-java-container/tree/master/samples/micronaut/pet-store)


この記事の関連情報としてJJUG CCC 2019 Fallの登壇資料がありますので、参考にしてください。


[![サーバーレス時代のJavaについて](https://image.slidesharecdn.com/20191123-jjug-serverlessjavaforpublic-191129053841/95/serverlessjava-1-638.jpg)](https://www.slideshare.net/AmazonWebServicesJapan/serverlessjava-199195000)
[サーバーレス時代のJavaについて](https://www.slideshare.net/AmazonWebServicesJapan/serverlessjava-199195000)