Spring Cloud Functionとは?
Spring Cloud Functionは、Springプロジェクトによって提供されている関数型プログラミングモデルを利用したServerless対応フレームワークです。
Spring BootアプリケーションをAWS LambdaやAzure Functions、Google Cloud Functionsなどに簡単にデプロイできます。
KotlessというJetBrainsのフレームワークもあるが・・・
Kotlin対応のServerlessフレームワークとしてはKotlessもありますが、最終commitが2022年3月28日です。
以前は私も注目していて使ってみたこともあるのですが、残念ながら更新されていないようです。
そのため、新たなKotlinでのServerless開発の選択肢として、Spring Cloud Functionを紹介します。
導入
IntelliJ IDEAからKotlinのGradleプロジェクトを作成し、以下の実装をしていきます。
Gradleの設定
まず、build.gradle.ktsは以下のようになります。
plugins {
kotlin("jvm") version "2.1.20"
kotlin("plugin.spring") version "2.1.20"
id("com.github.johnrengelman.shadow") version "8.1.1"
id("org.springframework.boot") version "3.5.0"
id("io.spring.dependency-management") version "1.1.7"
}
group = "org.example"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
}
dependencies {
testImplementation(kotlin("test"))
implementation("org.springframework.boot:spring-boot-starter")
implementation("org.springframework.cloud:spring-cloud-function-adapter-aws:4.3.0")
implementation("org.springframework.cloud:spring-cloud-starter-function-web:4.3.0")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
}
tasks {
shadowJar {
archiveClassifier.set("aws")
append("META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports")
manifest {
attributes(
mapOf(
"Main-Class" to "org.springframework.cloud.function.adapter.aws.FunctionInvoker",
"Start-Class" to "com.example.Application"
)
)
}
}
build {
dependsOn(shadowJar)
}
}
tasks.test {
useJUnitPlatform()
}
kotlin {
jvmToolchain(21)
}
Spring Cloud Functionの依存関係
まずポイントとしては、Spring Cloud Functionに関する以下の依存関係の追加です。
implementation("org.springframework.cloud:spring-cloud-function-adapter-aws:4.3.0")
implementation("org.springframework.cloud:spring-cloud-starter-function-web:4.3.0")
spring-cloud-function-adapter-aws
はAWS Lambdaでアプリケーションを動かすためのAdapterで、実装したSpringアプリケーションをデプロイ(後述)することで、Lambdaの関数として実行できるようにしてくれます。
org.springframework.cloud:spring-cloud-starter-function-web
は通常のウェブアプリケーションとして起動するためのモジュールで、local環境でのデバッグ(後述)時に使います。
Shadowでfat Jarを作る
KotlinやJavaのアプリケーションをLambdaにデプロイするには、fat Jar(アプリケーションとその依存ライブラリを全て1つのJarファイルにまとめたもの)を作り、アップロードする必要があります。
そのためにshadowというプラグインを使用し、以下の設定を追加します。
tasks {
shadowJar {
archiveClassifier.set("aws")
append("META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports")
manifest {
attributes(
mapOf(
"Main-Class" to "org.springframework.cloud.function.adapter.aws.FunctionInvoker",
"Start-Class" to "com.example.Application",
)
)
}
}
build {
dependsOn(shadowJar)
}
}
Main-Class
にはFunctionInvoker
というSpring Cloud Functionのクラスを指定する必要があります。
Start-Class
には、@SpringBootApplication
を付けているエントリポイントとなるクラス(後述)を指定します。
アプリケーションの実装
実行する関数として、以下のクラスを作成します。
package com.example
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.util.function.Function
data class Request(val name: String)
data class Response(val message: String)
@Configuration
class DemoHandler {
@Bean
fun hello(): Function<Request, Response> = Function { request ->
Response("Hello, ${request.name}!")
}
}
requestで文字列を受け取り、その値を埋め込んだ文字列をresponseとして返すだけの処理です。
関数の戻り値の型をjava.util.function.Function
で定義します。
そして以下のエントリポイントを作成します。
package com.example
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class Application
fun main(args: Array<String>) {
runApplication<Application>(*args)
}
Lambdaの関数として実行するだけであればmain関数の引数と処理は空でも問題ありませんが、localで実行して確認するために、通常のSpring Bootのアプリケーションと同じようにrunApplication
を使用して定義しています。
local環境での動作確認
Spring Cloud Functionでは、spring-cloud-starter-function-web
を使うことで、HTTPサーバー経由で実行が可能です。
これにより、Lambdaにデプロイせずとも関数の挙動を確認できます。
1. ローカルHTTPサーバー起動
前述のエントリポイントを作成していることで、./gradlew bootRun
でアプリケーションを起動し、HTTP経由で関数呼び出しができるようになります。
2. curlで関数を実行
デフォルトではポート8080でサーバが起動します。
例えば hello
関数をテストするには以下のようにPOSTします。
curl -X POST http://localhost:8080/hello \
-H "Content-Type: application/json" \
-d '{ "name": "Kotlin" }'
レスポンス例:
{
"message": "Hello, Kotlin!"
}
AWS Lambdaでのデプロイ
localで関数の処理は確認できたので、いよいよAWS Lambdaにデプロイします。
1. ./gradlew build
でビルド
build/libs/xxx(プロジェクト名)-aws.jar
というファイルができます。
いくつかjarファイルができると思いますが、awsというsuffixがついているものが、今回のデプロイで使うjarになります。
前述のbuild.gradle.ktsのarchiveClassifier.set("aws")
という部分でこのsuffixを指定しています。
2. build/libs/xxx-aws.jar
をAWS Lambda関数にアップロード
以下を参考にしてください。
ログインし、マネジメントコンソールから関数を作成し、今回ビルドしたjarをアップロードします。
3. Handlerの指定
アップロード後、Runtime settingsのHandlerに以下を設定します。
org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest
設定後の参考例は以下になります。
テストの実行
1. AWS Lambda コンソールを開く
マネジメントコンソールで当該ののLambda関数を選択します。
2. 「Test」タブを開く
関数の画面で上部にある「Test」タブを押します。
3. テストイベントを作成
初回の場合、テストイベントの作成画面が表示されます。
- Template:
Hello World
を選んでもOK - Event JSONを以下に変更:
{
"name": "Kotlin"
}
これは Request(name: String)
型のリクエストに対応しています。
Testの設定の参考例は以下です。
4. テスト実行
「Test」ボタンを押して実行すると、Spring Cloud Function が呼び出され、結果が表示されます。
5. レスポンス例(成功時)
{
"message": "Hello, Kotlin!"
}
以下のようにログが表示されます。
まとめ
- Spring Cloud Functionを使えば、KotlinでServerlessアプリケーションの関数が簡単に書ける
- 各種Adapterのモジュールで、AWS Lambdaなどのマネジメントサービスにもかんたデプロイできる
- Spring Frameworkの実装に慣れている人には、学習コストも低く導入できる
KotlinでServerlessアプリケーションを開発したい方にとって、Spring Cloud Functionは一つの有力な選択肢になるのではないかと思います。