Azure基本

spring-cloud-function-dependenciesのバージョンを最新(3.1.2)にしてみた

これまでこのブログで取り上げてきたAzure Functionsのサンプルプログラムでは、spring-cloud-function-dependenciesのバージョンを2.0.1.RELEASEとしてきたが、2021年4月13日現在の最新(2021年3月16日リリース)バージョンである3.1.2に変更することで、1つのAzure Functions内に複数のファンクションを含む場合にSpring Bootが初期化されることの不具合が解消できていることが分かった。

今回は、以前作成したサンプルプログラム内に含まれているspring-cloud-function-dependenciesのバージョンを最新(3.1.2)に変更してみたので、共有する。

なお、1つのAzure Functions内に複数のファンクションを含む場合にSpring Bootが初期化されることの不具合が解消できていることについては、以下のサイトを参照のこと。
https://github.com/spring-cloud/spring-cloud-function/issues/600

前提条件

下記記事の実装が完了していること。

Azure App ServiceとAzure Functionsの共通クラスを別プロジェクトに取り出してみたこれまでこのブログで取り上げてきたAzureのサンプルプログラムの中には、Azure App ServiceとAzure Functio...

作成したサンプルプログラム(Azure Functions側)の内容

作成したサンプルプログラム(Azure Functions側)の構成は以下の通り。なお、App Services側のソースコードと共通クラス格納用プロジェクトについては、修正していない。
サンプルプログラムの構成
なお、上記の赤枠は、前提条件のプログラムから追加・変更したプログラムである。

pom.xmlの変更内容は以下の通りで、spring-cloud-function-dependenciesのバージョンを3.1.2に変更している。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-function-dependencies</artifactId>
<version>3.1.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-function-dependencies</artifactId> <version>3.1.2</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-function-dependencies</artifactId>
            <version>3.1.2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

また、Handlerクラスの内容は以下の通りで、継承するクラスを「AzureSpringBootRequestHandler」クラスから「FunctionInvoker」クラスに変更している。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
package com.example;
import java.util.Optional;
import org.springframework.cloud.function.adapter.azure.FunctionInvoker;
import com.example.model.FileUploadParam;
import com.example.model.FileUploadResult;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.microsoft.azure.functions.ExecutionContext;
import com.microsoft.azure.functions.HttpMethod;
import com.microsoft.azure.functions.HttpRequestMessage;
import com.microsoft.azure.functions.HttpResponseMessage;
import com.microsoft.azure.functions.HttpStatus;
import com.microsoft.azure.functions.annotation.AuthorizationLevel;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.annotation.HttpTrigger;
public class FileUploadHandler
extends FunctionInvoker<FileUploadParam, FileUploadResult> {
/**
* HTTP要求に応じて、DemoAzureFunctionクラスのfileUploadメソッドを呼び出し、
* その戻り値をボディに設定したレスポンスを返す.
* @param request リクエストオブジェクト
* @param context コンテキストオブジェクト
* @return レスポンスオブジェクト
*/
@FunctionName("fileUpload")
public HttpResponseMessage execute(
@HttpTrigger(name = "request"
, methods = HttpMethod.POST, authLevel = AuthorizationLevel.ANONYMOUS)
HttpRequestMessage<Optional<String>> request,
ExecutionContext context) {
// リクエストオブジェクトからパラメータ値を取得し、ファイルアップロード用Paramに設定する
ObjectMapper mapper = new ObjectMapper();
String jsonParam = request.getBody().get();
jsonParam = jsonParam.replaceAll("\\[", "").replaceAll("\\]", "");
FileUploadParam fileUploadParam = new FileUploadParam();
try {
fileUploadParam = mapper.readValue(
jsonParam, new TypeReference<FileUploadParam>() {
});
} catch (Exception ex) {
throw new RuntimeException(ex);
}
// handleRequestメソッド内でDemoAzureFunctionクラスのfileUploadメソッドを呼び出し、
// その戻り値をボディに設定したレスポンスを、JSON形式で返す
return request.createResponseBuilder(HttpStatus.OK)
.body(handleRequest(fileUploadParam, context))
.header("Content-Type", "text/json").build();
}
package com.example; import java.util.Optional; import org.springframework.cloud.function.adapter.azure.FunctionInvoker; import com.example.model.FileUploadParam; import com.example.model.FileUploadResult; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.microsoft.azure.functions.ExecutionContext; import com.microsoft.azure.functions.HttpMethod; import com.microsoft.azure.functions.HttpRequestMessage; import com.microsoft.azure.functions.HttpResponseMessage; import com.microsoft.azure.functions.HttpStatus; import com.microsoft.azure.functions.annotation.AuthorizationLevel; import com.microsoft.azure.functions.annotation.FunctionName; import com.microsoft.azure.functions.annotation.HttpTrigger; public class FileUploadHandler extends FunctionInvoker<FileUploadParam, FileUploadResult> { /** * HTTP要求に応じて、DemoAzureFunctionクラスのfileUploadメソッドを呼び出し、 * その戻り値をボディに設定したレスポンスを返す. * @param request リクエストオブジェクト * @param context コンテキストオブジェクト * @return レスポンスオブジェクト */ @FunctionName("fileUpload") public HttpResponseMessage execute( @HttpTrigger(name = "request" , methods = HttpMethod.POST, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request, ExecutionContext context) { // リクエストオブジェクトからパラメータ値を取得し、ファイルアップロード用Paramに設定する ObjectMapper mapper = new ObjectMapper(); String jsonParam = request.getBody().get(); jsonParam = jsonParam.replaceAll("\\[", "").replaceAll("\\]", ""); FileUploadParam fileUploadParam = new FileUploadParam(); try { fileUploadParam = mapper.readValue( jsonParam, new TypeReference<FileUploadParam>() { }); } catch (Exception ex) { throw new RuntimeException(ex); } // handleRequestメソッド内でDemoAzureFunctionクラスのfileUploadメソッドを呼び出し、 // その戻り値をボディに設定したレスポンスを、JSON形式で返す return request.createResponseBuilder(HttpStatus.OK) .body(handleRequest(fileUploadParam, context)) .header("Content-Type", "text/json").build(); }
package com.example;

import java.util.Optional;

import org.springframework.cloud.function.adapter.azure.FunctionInvoker;

import com.example.model.FileUploadParam;
import com.example.model.FileUploadResult;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.microsoft.azure.functions.ExecutionContext;
import com.microsoft.azure.functions.HttpMethod;
import com.microsoft.azure.functions.HttpRequestMessage;
import com.microsoft.azure.functions.HttpResponseMessage;
import com.microsoft.azure.functions.HttpStatus;
import com.microsoft.azure.functions.annotation.AuthorizationLevel;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.annotation.HttpTrigger;

public class FileUploadHandler 
    extends FunctionInvoker<FileUploadParam, FileUploadResult> {

    /**
     * HTTP要求に応じて、DemoAzureFunctionクラスのfileUploadメソッドを呼び出し、
     * その戻り値をボディに設定したレスポンスを返す.
     * @param request リクエストオブジェクト
     * @param context コンテキストオブジェクト
     * @return レスポンスオブジェクト
     */
    @FunctionName("fileUpload")
    public HttpResponseMessage execute(
            @HttpTrigger(name = "request"
                , methods = HttpMethod.POST, authLevel = AuthorizationLevel.ANONYMOUS) 
                    HttpRequestMessage<Optional<String>> request,
            ExecutionContext context) {

        // リクエストオブジェクトからパラメータ値を取得し、ファイルアップロード用Paramに設定する
        ObjectMapper mapper = new ObjectMapper();
        String jsonParam = request.getBody().get();
        jsonParam = jsonParam.replaceAll("\\[", "").replaceAll("\\]", "");

        FileUploadParam fileUploadParam = new FileUploadParam();
        try {
            fileUploadParam = mapper.readValue(
                jsonParam, new TypeReference<FileUploadParam>() {
            });
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }

        // handleRequestメソッド内でDemoAzureFunctionクラスのfileUploadメソッドを呼び出し、
        // その戻り値をボディに設定したレスポンスを、JSON形式で返す
        return request.createResponseBuilder(HttpStatus.OK)
            .body(handleRequest(fileUploadParam, context))
            .header("Content-Type", "text/json").build();
    }
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
package com.example;
import java.util.Optional;
import org.springframework.cloud.function.adapter.azure.FunctionInvoker;
import com.example.model.GetFileListParam;
import com.example.model.GetFileListResult;
import com.microsoft.azure.functions.ExecutionContext;
import com.microsoft.azure.functions.HttpMethod;
import com.microsoft.azure.functions.HttpRequestMessage;
import com.microsoft.azure.functions.HttpResponseMessage;
import com.microsoft.azure.functions.HttpStatus;
import com.microsoft.azure.functions.annotation.AuthorizationLevel;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.annotation.HttpTrigger;
public class GetFileListHandler
extends FunctionInvoker<GetFileListParam, GetFileListResult> {
/**
* HTTP要求に応じて、DemoAzureFunctionクラスのfileUploadメソッドを呼び出し、
* その戻り値をボディに設定したレスポンスを返す.
* @param request リクエストオブジェクト
* @param context コンテキストオブジェクト
* @return レスポンスオブジェクト
*/
@FunctionName("getFileList")
public HttpResponseMessage execute(
@HttpTrigger(name = "request"
, methods = HttpMethod.POST, authLevel = AuthorizationLevel.ANONYMOUS)
HttpRequestMessage<Optional<String>> request,
ExecutionContext context) {
// handleRequestメソッド内でDemoAzureFunctionクラスのfileUploadメソッドを
// 呼び出し、その戻り値をボディに設定したレスポンスを、JSON形式で返す
return request.createResponseBuilder(HttpStatus.OK)
.body(handleRequest(new GetFileListParam(), context))
.header("Content-Type", "text/json").build();
}
}
package com.example; import java.util.Optional; import org.springframework.cloud.function.adapter.azure.FunctionInvoker; import com.example.model.GetFileListParam; import com.example.model.GetFileListResult; import com.microsoft.azure.functions.ExecutionContext; import com.microsoft.azure.functions.HttpMethod; import com.microsoft.azure.functions.HttpRequestMessage; import com.microsoft.azure.functions.HttpResponseMessage; import com.microsoft.azure.functions.HttpStatus; import com.microsoft.azure.functions.annotation.AuthorizationLevel; import com.microsoft.azure.functions.annotation.FunctionName; import com.microsoft.azure.functions.annotation.HttpTrigger; public class GetFileListHandler extends FunctionInvoker<GetFileListParam, GetFileListResult> { /** * HTTP要求に応じて、DemoAzureFunctionクラスのfileUploadメソッドを呼び出し、 * その戻り値をボディに設定したレスポンスを返す. * @param request リクエストオブジェクト * @param context コンテキストオブジェクト * @return レスポンスオブジェクト */ @FunctionName("getFileList") public HttpResponseMessage execute( @HttpTrigger(name = "request" , methods = HttpMethod.POST, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request, ExecutionContext context) { // handleRequestメソッド内でDemoAzureFunctionクラスのfileUploadメソッドを // 呼び出し、その戻り値をボディに設定したレスポンスを、JSON形式で返す return request.createResponseBuilder(HttpStatus.OK) .body(handleRequest(new GetFileListParam(), context)) .header("Content-Type", "text/json").build(); } }
package com.example;

import java.util.Optional;

import org.springframework.cloud.function.adapter.azure.FunctionInvoker;

import com.example.model.GetFileListParam;
import com.example.model.GetFileListResult;
import com.microsoft.azure.functions.ExecutionContext;
import com.microsoft.azure.functions.HttpMethod;
import com.microsoft.azure.functions.HttpRequestMessage;
import com.microsoft.azure.functions.HttpResponseMessage;
import com.microsoft.azure.functions.HttpStatus;
import com.microsoft.azure.functions.annotation.AuthorizationLevel;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.annotation.HttpTrigger;

public class GetFileListHandler 
    extends FunctionInvoker<GetFileListParam, GetFileListResult> {

    /**
     * HTTP要求に応じて、DemoAzureFunctionクラスのfileUploadメソッドを呼び出し、
     * その戻り値をボディに設定したレスポンスを返す.
     * @param request リクエストオブジェクト
     * @param context コンテキストオブジェクト
     * @return レスポンスオブジェクト
     */
    @FunctionName("getFileList")
    public HttpResponseMessage execute(
            @HttpTrigger(name = "request"
                , methods = HttpMethod.POST, authLevel = AuthorizationLevel.ANONYMOUS) 
                    HttpRequestMessage<Optional<String>> request,
            ExecutionContext context) {

        // handleRequestメソッド内でDemoAzureFunctionクラスのfileUploadメソッドを
        // 呼び出し、その戻り値をボディに設定したレスポンスを、JSON形式で返す
        return request.createResponseBuilder(HttpStatus.OK)
            .body(handleRequest(new GetFileListParam(), context))
            .header("Content-Type", "text/json").build();
    }
}



このように変更した背景としては、spring-cloud-function-dependenciesのバージョンを3.1.2に変更すると、以下のように「AzureSpringBootRequestHandler」クラスを使うべきでないという警告が出て、実際に「AzureSpringBootRequestHandler」クラスの警告を確認すると「FunctionInvoker」を使うように書かれているためである。
FunctionInvoker_1

FunctionInvoker_2

なお、修正したソースコード全体の内容は、以下のサイトを参照のこと。
https://github.com/purin-it/azure/tree/master/azure-function-dependencies-312/

サンプルプログラムの実行

サンプルプログラムの実行結果は、以下の記事の「作成したサンプルプログラムの実行結果」と同じになる。

Azure FunctionsでAzure Blob Storageのコンテナからファイルをダウンロードしてみた以前、Azure FunctionsでAzure Blob Storageのコンテナー内にファイルを格納する処理を実施してみたが、今回は...

要点まとめ

  • spring-cloud-function-dependenciesのバージョンを3.1.2に変更すると、1つのAzure Functions内に複数のファンクションを含む場合にSpring Bootが初期化されることの不具合が解消できている。
  • spring-cloud-function-dependenciesのバージョンを3.1.2に変更した場合は、Handlerクラスで継承するクラスを「AzureSpringBootRequestHandler」クラスから「FunctionInvoker」クラスに変更する。