Azure Functionsのお勉強メモ(2)Spring Cloud FunctionでHTTP Triggerを実装する

最近、Azure Functionsのお勉強をチマチマと始めました。色々と分からないことが多かったのでお勉強メモをまとめて記します。

どこまで続くかわからないお勉強メモ。今日は2回目です。今回はJavaです。前回はNode.jsで実装しました。

miyohide.hatenablog.com

JavaでのAzure Functions

Azure FunctionsでのアプリをJavaで実装してみます。Mavenではmvn archetype:generateでプロジェクトが生成できるので大変楽そうなのですが、あまりXMLファイルを書きたくなかったので、自分はGradleを使うようにしました。

docs.microsoft.com

過去にも似たようなことをやりましたが、Spring Cloud Functionのバージョンが上がっていたので改めてやり直し。

miyohide.hatenablog.com

ここでは上には記されていないことを中心に記述します。

Spring Cloud Function

将来的にRDBMSとの接続をすることを考えて、Spring Cloud Functionというフレームワークを使うことにしました。Spring Cloud Functionを使った記事はAzureのドキュメントにもあります。

docs.microsoft.com

上記にあるサンプルでもいいのですが、私はSpring Cloud Functionのサンプルを参考にしました。

docs.spring.io

これを書いている2021年3月21日ではSpring Cloud Functionは3.1.2で、前バージョンとはいくつか仕様変更が発生しています。

具体的には、3.1.1ではAzureSpringBootRequestHandlerを継承する必要がありましたが、3.1.2ではFunctionInvokerを継承する必要があるようです(正確には、AzureSpringBootRequestHandlerは非推奨化)。詳細はそれぞれのドキュメントを見ると良いかと思います。

3.1.1のもの https://docs.spring.io/spring-cloud-function/docs/3.1.1/reference/html/index.html

3.1.2のもの https://docs.spring.io/spring-cloud-function/docs/3.1.2/reference/html/index.html

build.gradle

build.gradleにてAzure Functionsにデプロイする情報を記述します。記述する内容の詳細については以下のwikiをみると良いでしょう。

github.com

今回はJava 11環境で動かしたかったのですが、runtimeに何も指定しないとJava 8の環境になるようです。以下のようにruntimejavaVersionを設定するとJava 11で生成されました。

azurefunctions {
    resourceGroup = 'sample_resource_group'
    appName = "sample_app_name"
    pricingTier = "Consumption"
    region = "japaneast"
    runtime {
        os = "windows"
        javaVersion = 11
    }
}

f:id:miyohide:20210322210705p:plain

これでAzureにデプロイすると動くはずだったのですが、以下のログが出力され500エラーが発生しました。

2021-03-21T06:59:56.612 [Error] Executed 'Functions.hello' (Failed, Id=exxxxxxxxxx, Duration=638ms)Result: FailureException: IllegalArgumentException: Failed to locate main classStack: java.lang.IllegalStateException: Failed to discover main class. An attempt was made to discover main class as 'MAIN_CLASS' environment variable, system property as well as entry in META-INF/MANIFEST.MF (in that order).at org.springframework.cloud.function.utils.FunctionClassUtils.getStartClass(FunctionClassUtils.java:83)

この問題を解決するにはbuild.gradleに以下の設定を追加します。この設定はマニフェストファイルにメインクラスのクラス名を指定して、実行可能なjarファイルとして生成することを意味しています。

jar {
    manifest {
        attributes 'Main-Class' : 'com.github.miyohide.Funcapp'
    }
}

FunctionとかSupplierとかConsumerとか

Spring Cloud Functionを使おうとするとちょっと面食らうのがFunction。 これは、Java 8から導入されたJava関数型インターフェースというもの。

www.ne.jp

ちょっと書き方が慣れないけれども、徐々に慣れていくしかないかなと。

テスト

テストを書くこともやってみました。build.gradleでのライブラリ指定をとりあえず以下のようにしました。

dependencies {
    implementation 'org.springframework.cloud:spring-cloud-function-adapter-azure:3.1.2'
    testImplementation 'org.springframework.cloud:spring-cloud-starter-function-web:3.1.2'
    testImplementation 'org.springframework.boot:spring-boot-starter-test:2.4.3'
}

spring-boot-starter-testのバージョンを指定するのがちょっといまいちなのでなんとかしたいところ...

JUnit 5ではbuild.gradleにて以下の記述がないとうまくテストが認識されません。

test {
    useJUnitPlatform()
}

参考

junit.org

テストの書き方ついては以下を参照。

www.ne.jp

デプロイ

gradlew azureFunctionsDeployを実行するとAzure上にデプロイされます。早速、Application Insightsでrequestsテーブルを参照し、処理時間がどれぐらいかかるかをみてみました。

f:id:miyohide:20210322211044p:plain

デプロイ後、最初のアクセスには概ね6秒ぐらい処理時間がかかるようでした。高々数回しか試していないですし、フレームワーク使用の有無といった差もあるので、前回のNode.jsとの比較(4.6秒)はあまり意味がないかなと思います。倍ぐらいの差がつくのならともかく、高々数秒でしたら好きな言語やフレームワークを使えばいいかなと思います。

ソース

本ブログ記述時点でのソースです。

github.com