Azure Functions の Java 開発者向けガイド

このガイドでは、Java を使用した Azure Functions の開発を成功させるために役立つ詳細情報について説明します。

Java 開発者が、Azure Functions を初めて使用する場合は、まず次のいずれかの記事を読むことをお勧めします。

作業の開始 概念 シナリオとサンプル

Java 関数の基礎

Java 関数は、注釈 @FunctionName で装飾された public メソッドです。 このメソッドは、Java 関数のエントリを定義し、特定のパッケージ内で一意である必要があります。 パッケージには、@FunctionName で注釈付けされたパブリック メソッドを複数持つクラスが複数存在することもあります。 1 つのパッケージが Azure の関数アプリにデプロイされます。 Azure では、関数アプリによって個々の Java 関数のデプロイ、実行、管理コンテキストが提供されます。

プログラミング モデル

トリガーとバインドの概念は、Azure Functions の基盤です。 トリガーによって、コードの実行が開始します。 バインドでは、データを関数に渡し、関数からデータを返す方法が提供されます。カスタム データ アクセス コードを記述する必要はありません。

Java の関数を作成する

Java の関数を作成しやすくするために、Maven ベースのツールとアーキタイプが用意されています。事前に定義された Java テンプレートを使用することで、特定の関数トリガーを含むプロジェクトを簡単に作成できます。

Maven ベースのツール

次の開発環境には、Java 関数プロジェクトの作成に対応した Azure Functions ツールが備わっています。

これらの記事には、好みの IDE を使用して基本的な関数を作成する方法が紹介されています。

プロジェクトのスキャフォールディング

ターミナルからのコマンド ライン開発を希望する場合、Java ベースの関数プロジェクトをスキャフォールディングする最も簡単な方法は、Apache Maven アーキタイプを使用することです。 Azure Functions の Java Maven アーキタイプは、com.microsoft.azure:azure-functions-archetype という groupId:artifactId で発行されています。

次のコマンドを使用すると、このアーキタイプを使用して新しい Java 関数プロジェクトが生成されます。

mvn archetype:generate \
    -DarchetypeGroupId=com.microsoft.azure \
    -DarchetypeArtifactId=azure-functions-archetype

このアーキタイプの基本的な使い方については、Java クイックスタートを参照してください。

フォルダー構造

Azure Functions の Java プロジェクトのフォルダー構造を次に示します。

FunctionsProject
 | - src
 | | - main
 | | | - java
 | | | | - FunctionApp
 | | | | | - MyFirstFunction.java
 | | | | | - MySecondFunction.java
 | - target
 | | - azure-functions
 | | | - FunctionApp
 | | | | - FunctionApp.jar
 | | | | - host.json
 | | | | - MyFirstFunction
 | | | | | - function.json
 | | | | - MySecondFunction
 | | | | | - function.json
 | | | | - bin
 | | | | - lib
 | - pom.xml

共有 host.json ファイルを使用して関数アプリを構成できます。 各関数には、独自のコード ファイル (.java) とバインディング構成ファイル (function.json) があります。

1 つのプロジェクトに複数の関数を含めることができます。 複数の jar に関数を分けることは避けてください。 ターゲット ディレクトリの FunctionApp が、Azure 内の関数アプリにデプロイされます。

トリガーと注釈

関数は、HTTP 要求、タイマー、日付の更新などのトリガーで呼び出されます。 関数はそのトリガーと他の入力を処理して 1 つまたは複数の出力を生成する必要があります。

com.microsoft.azure.functions.annotation.* パッケージに含まれる Java の注釈を使用して、入力と出力をメソッドにバインドします。 詳細については、Java リファレンス ドキュメントに関するページを参照してください。

重要

Azure Blob storage、Azure Queue storage、または Azure Table Storage をローカルで実行するには、local.settings.json に Azure Storage アカウントを構成する必要があります。

例:

public class Function {
    public String echo(@HttpTrigger(name = "req", 
      methods = {HttpMethod.POST},  authLevel = AuthorizationLevel.ANONYMOUS) 
        String req, ExecutionContext context) {
        return String.format(req);
    }
}

azure-functions-maven-plugin によって生成された、対応する function.json を次に示します。

{
  "scriptFile": "azure-functions-example.jar",
  "entryPoint": "com.example.Function.echo",
  "bindings": [
    {
      "type": "httpTrigger",
      "name": "req",
      "direction": "in",
      "authLevel": "anonymous",
      "methods": [ "GET","POST" ]
    },
    {
      "type": "http",
      "name": "$return",
      "direction": "out"
    }
  ]
}

Java のバージョン

Azure でアプリを実行する際の Java のバージョンは、pom.xml ファイルで指定します。 Maven アーキタイプでは現在、Java 8 用の pom.xml が生成され、これは、発行前に変更できます。 pom.xml の Java バージョンは、アプリをローカルで開発してテストしたバージョンと一致している必要があります。

サポートされているバージョン

次の表は、Functions ランタイムの各メジャー バージョンに対して現在サポートされている Java バージョンをオペレーティング システムごとに示しています。

Functions バージョン Java バージョン (Windows) Java バージョン (Linux)
4.x 17
11
8
21 (プレビュー)
17
11
8
3.x 11
8
11
8
2.x 8 該当なし

デプロイのための Java バージョンを指定しない限り、Azure へのデプロイ中、Maven アーキタイプは既定で Java 8 になります。

デプロイ バージョンを指定する

Maven アーキタイプが対象とする Java のバージョンは、-DjavaVersion パラメーターを使用して制御できます。 このパラメーターの値は、81117、または 21 にできます。

Maven アーキタイプでは、指定された Java バージョンを対象とする pom.xml が生成されます。 pom.xml 内の次の要素は、使用する Java バージョンを示しています。

要素 Java 8 の値 Java 11 の値 Java 17 の合値 Java 21 の値 (プレビュー、Linux) 説明
Java.version 1.8 11 17 21 maven-compiler-plugin によって使用される Java のバージョン。
JavaVersion 8 11 17 21 Azure の関数アプリによってホストされる Java バージョン。

次の例に、pom.xml ファイルの関連セクションにある Java 8 の設定を示します。

Java.version

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
    <azure.functions.maven.plugin.version>1.6.0</azure.functions.maven.plugin.version>
    <azure.functions.java.library.version>1.3.1</azure.functions.java.library.version>
    <functionAppName>fabrikam-functions-20200718015742191</functionAppName>
    <stagingDirectory>${project.build.directory}/azure-functions/${functionAppName}</stagingDirectory>
</properties>

JavaVersion

<runtime>
    <!-- runtime os, could be windows, linux or docker-->
    <os>windows</os>
    <javaVersion>8</javaVersion>
    <!-- for docker function, please set the following parameters -->
    <!-- <image>[hub-user/]repo-name[:tag]</image> -->
    <!-- <serverId></serverId> -->
    <!-- <registryUrl></registryUrl>  -->
</runtime>

重要

JAVA_HOME 環境変数に、Maven を使用したコードのコンパイル時に使用される JDK ディレクトリが正しく設定されている必要があります。 JDK のバージョンが少なくとも Java.version 設定と同じであることを確認します。

デプロイ OS を指定する

また、Maven では、Azure で関数アプリを実行するオペレーティング システムを指定することもできます。 os 要素を使用して、オペレーティング システムを選択します。

要素 Windows Linux Docker
os windows linux docker

次の例は、pom.xml ファイルの runtime セクションのオペレーティング システム設定を示しています。

<runtime>
    <!-- runtime os, could be windows, linux or docker-->
    <os>windows</os>
    <javaVersion>8</javaVersion>
    <!-- for docker function, please set the following parameters -->
    <!-- <image>[hub-user/]repo-name[:tag]</image> -->
    <!-- <serverId></serverId> -->
    <!-- <registryUrl></registryUrl>  -->
</runtime>

JDK ランタイムの使用可能性とサポート

OpenJDK の Microsoft と Adoptium のビルドが、Functions for Java 8 (Adoptium)、Java 11、17、21 (MSFT) で提供およびサポートされています。 これらのバイナリは、Azure 向け OpenJDK の、実稼働可能なマルチプラットフォームの無料ディストリビューションとして提供されています。 これらには、Java SE アプリケーションを構築および実行するためのすべてのコンポーネントが含まれています。

ローカル開発またはテストの場合は、OpenJDK の Microsoft ビルドまたは Adoptium Temurin のバイナリを無料でダウンロードできます。 JKD および関数アプリに関する問題に対する Azure サポートは、認定サポート プランを通じてご利用いただけます。

関数アプリで Zulu for Azure バイナリを引き続き使用する場合は、必要に応じてアプリを構成してください。 お使いのサイトでは、引き続き Azul バイナリを使用できます。 ただし、セキュリティ パッチや機能強化は、新しいバージョンの OpenJDK でのみ使用できます。 このため、使用可能な最新バージョンの Java がアプリで使用されるように、最終的にはこの構成を削除する必要があります。

JVM のカスタマイズ

関数を使用すると、お使いの Java 関数の実行に使用する Java 仮想マシン (JVM) をカスタマイズできます。 既定で次の JVM オプションが使用されます。

  • -XX:+TieredCompilation
  • -XX:TieredStopAtLevel=1
  • -noverify
  • -Djava.net.preferIPv4Stack=true
  • -jar

プランの種類に応じて、次のいずれかのアプリケーション設定を使用して、JVM に他の引数を指定できます。

プランの種類 設定名 コメント
従量課金プラン languageWorkers__java__arguments この設定によって、従量課金プランで実行されている Java 関数のコールド スタート時間が長くなります。
Premium プラン
専用プラン
JAVA_OPTS

次のセクションでは、これらの設定を追加する方法について説明します。 アプリケーション設定の操作の詳細については、「アプリケーション設定を操作する」セクションを参照してください。

Azure portal

Azure portal[アプリケーション設定] タブを使用して languageWorkers__java__arguments または JAVA_OPTS の設定を追加します。

Azure CLI

次の -Djava.awt.headless=true オプションの例に示すように、az functionapp config appsettings set コマンドを使用してこれらの設定を追加できます。

az functionapp config appsettings set \
    --settings "languageWorkers__java__arguments=-Djava.awt.headless=true" \
    --name <APP_NAME> --resource-group <RESOURCE_GROUP>

この例では、ヘッドレス モードが有効になります。 <APP_NAME> をお使いの関数アプリ名に置き換え、<RESOURCE_GROUP> をリソース グループに置き換えます。

サードパーティ製ライブラリ

Azure Functions はサード パーティ製ライブラリの使用をサポートしています。 既定で、プロジェクトの pom.xml ファイルで指定されているすべての依存関係は、mvn package 目標の間に自動的にバンドルされます。 pom.xml ファイルの依存関係として指定されていないライブラリの場合は、関数のルート ディレクトリ以下の lib ディレクトリに配置します。 lib ディレクトリに配置された依存関係は、実行時にシステム クラス ローダーに追加されます。

com.microsoft.azure.functions:azure-functions-java-library 依存関係はクラスパスにおいて既定で提供されており、lib ディレクトリに含める必要はありません。 また、azure-functions-java-worker は、ここに示されている依存関係をクラスパスに追加します。

データ型のサポート

Plain old Java object (POJO)、azure-functions-java-library 内で定義されている型、または文字列や整数などのプリミティブなデータ型を使用して入力または力バインドにバインドできます。

POJO

入力データを POJO に変換する場合、azure-functions-java-worker では gson ライブラリが使用されます。 関数への入力として使用される POJO の型は public である必要があります。

Binary Data

バイナリの入力または出力を byte[] にバインドするには、使用する function.json 内の dataType フィールドを binary に設定します。

   @FunctionName("BlobTrigger")
    @StorageAccount("AzureWebJobsStorage")
     public void blobTrigger(
        @BlobTrigger(name = "content", path = "myblob/{fileName}", dataType = "binary") byte[] content,
        @BindingName("fileName") String fileName,
        final ExecutionContext context
    ) {
        context.getLogger().info("Java Blob trigger function processed a blob.\n Name: " + fileName + "\n Size: " + content.length + " Bytes");
    }

null 値を期待する場合、Optional<T> を使用します。

バインド

入出力バインドによって、コード内からデータに接続する宣言型の方法が提供されます。 関数は複数の入出力バインドを持つことができます。

入力バインドの例

package com.example;

import com.microsoft.azure.functions.annotation.*;

public class Function {
    @FunctionName("echo")
    public static String echo(
        @HttpTrigger(name = "req", methods = { HttpMethod.PUT }, authLevel = AuthorizationLevel.ANONYMOUS, route = "items/{id}") String inputReq,
        @TableInput(name = "item", tableName = "items", partitionKey = "Example", rowKey = "{id}", connection = "AzureWebJobsStorage") TestInputData inputData,
        @TableOutput(name = "myOutputTable", tableName = "Person", connection = "AzureWebJobsStorage") OutputBinding<Person> testOutputData
    ) {
        testOutputData.setValue(new Person(httpbody + "Partition", httpbody + "Row", httpbody + "Name"));
        return "Hello, " + inputReq + " and " + inputData.getKey() + ".";
    }

    public static class TestInputData {
        public String getKey() { return this.rowKey; }
        private String rowKey;
    }
    public static class Person {
        public String partitionKey;
        public String rowKey;
        public String name;

        public Person(String p, String r, String n) {
            this.partitionKey = p;
            this.rowKey = r;
            this.name = n;
        }
    }
}

この関数は HTTP 要求を使用して呼び出します。

  • HTTP 要求のペイロードは、引数 inputReqString として渡されます。
  • 1 つのエントリが Table storage から取得され、引数 inputDataTestInputData として渡されます。

入力のバッチを受信するには、String[]POJO[]List<String> または List<POJO> にバインドできます。

@FunctionName("ProcessIotMessages")
    public void processIotMessages(
        @EventHubTrigger(name = "message", eventHubName = "%AzureWebJobsEventHubPath%", connection = "AzureWebJobsEventHubSender", cardinality = Cardinality.MANY) List<TestEventData> messages,
        final ExecutionContext context)
    {
        context.getLogger().info("Java Event Hub trigger received messages. Batch size: " + messages.size());
    }
    
    public class TestEventData {
    public String id;
}

この関数は、構成済みのイベント ハブに新しいデータが見つかるたびにトリガーされます。 cardinalityMANY に設定されているので、関数はイベント ハブからメッセージのバッチを受信します。 イベント ハブからの EventData は関数実行のために TestEventData に変換されます。

出力バインドの例

$return を使用して、出力バインディングを戻り値にバインドすることができます。

package com.example;

import com.microsoft.azure.functions.annotation.*;

public class Function {
    @FunctionName("copy")
    @StorageAccount("AzureWebJobsStorage")
    @BlobOutput(name = "$return", path = "samples-output-java/{name}")
    public static String copy(@BlobTrigger(name = "blob", path = "samples-input-java/{name}") String content) {
        return content;
    }
}

複数の出力バインディングが存在する場合は、そのうちの 1 つにのみ戻り値を使用します。

複数の出力値を送信するには、azure-functions-java-library パッケージに定義されている OutputBinding<T> を使用します。

@FunctionName("QueueOutputPOJOList")
    public HttpResponseMessage QueueOutputPOJOList(@HttpTrigger(name = "req", methods = { HttpMethod.GET,
            HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
            @QueueOutput(name = "itemsOut", queueName = "test-output-java-pojo", connection = "AzureWebJobsStorage") OutputBinding<List<TestData>> itemsOut, 
            final ExecutionContext context) {
        context.getLogger().info("Java HTTP trigger processed a request.");
       
        String query = request.getQueryParameters().get("queueMessageId");
        String queueMessageId = request.getBody().orElse(query);
        itemsOut.setValue(new ArrayList<TestData>());
        if (queueMessageId != null) {
            TestData testData1 = new TestData();
            testData1.id = "msg1"+queueMessageId;
            TestData testData2 = new TestData();
            testData2.id = "msg2"+queueMessageId;

            itemsOut.getValue().add(testData1);
            itemsOut.getValue().add(testData2);

            return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + queueMessageId).build();
        } else {
            return request.createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("Did not find expected items in CosmosDB input list").build();
        }
    }

     public static class TestData {
        public String id;
    }

この関数は HttpRequest オブジェクトで呼び出します。 複数の値を Queue storage に書き込みます。

HttpRequestMessage と HttpResponseMessage

これらは azure-functions-java-library で定義されます。 HttpTrigger 関数と共に機能するヘルパー型です。

特殊な型 移行先 一般的な用途
HttpRequestMessage<T> HTTP トリガー メソッド、ヘッダー、またはクエリを取得する
HttpResponseMessage HTTP 出力のバインド 200 以外の状態を返す

Metadata

いくつかのトリガーでは、入力データと共にトリガー メタデータが送信されます。 注釈 @BindingName を使用して、トリガー メタデータにバインドできます。

package com.example;

import java.util.Optional;
import com.microsoft.azure.functions.annotation.*;


public class Function {
    @FunctionName("metadata")
    public static String metadata(
        @HttpTrigger(name = "req", methods = { HttpMethod.GET, HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) Optional<String> body,
        @BindingName("name") String queryValue
    ) {
        return body.orElse(queryValue);
    }
}

上記の例では、queryValue は HTTP 要求 URL http://{example.host}/api/metadata?name=test 内のクエリ文字列パラメーター name にバインドされています。 次のもう 1 つの例では、キュー トリガー メタデータから Id にバインドする方法を示します。

 @FunctionName("QueueTriggerMetadata")
    public void QueueTriggerMetadata(
        @QueueTrigger(name = "message", queueName = "test-input-java-metadata", connection = "AzureWebJobsStorage") String message,@BindingName("Id") String metadataId,
        @QueueOutput(name = "output", queueName = "test-output-java-metadata", connection = "AzureWebJobsStorage") OutputBinding<TestData> output,
        final ExecutionContext context
    ) {
        context.getLogger().info("Java Queue trigger function processed a message: " + message + " with metadaId:" + metadataId );
        TestData testData = new TestData();
        testData.id = metadataId;
        output.setValue(testData);
    }

Note

注釈に指定されている名前がメタデータ プロパティと一致する必要があります。

実行コンテキスト

azure-functions-java-library 内で定義されている ExecutionContext には、関数ランタイムと通信するためのヘルパー メソッドが含まれています。 詳しくは、ExecutionContext のリファレンス記事をご覧ください。

ロガー

ExecutionContext 内で定義されている getLogger を使用して、関数コードからログを書き込みます。

例:


import com.microsoft.azure.functions.*;
import com.microsoft.azure.functions.annotation.*;

public class Function {
    public String echo(@HttpTrigger(name = "req", methods = {HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) String req, ExecutionContext context) {
        if (req.isEmpty()) {
            context.getLogger().warning("Empty request body received by function " + context.getFunctionName() + " with invocation " + context.getInvocationId());
        }
        return String.format(req);
    }
}

ログとトレースの表示

Java の stdout と stderr ログ、その他の各種アプリケーション ログは、Azure CLI を使用してストリーム配信できます。

Azure CLI を使用して、アプリケーション ログを書き込むように関数アプリを構成する方法を次に示します。

az webapp log config --name functionname --resource-group myResourceGroup --application-logging true

Azure CLI を使って関数アプリのログ出力をストリーム配信するには、コマンド プロンプト、Bash、ターミナルのいずれかのセッションを新たに開いて、次のコマンドを入力します。

az webapp log tail --name webappname --resource-group myResourceGroup

az webapp log tail コマンドには、--provider オプションを使って出力をフィルター処理するオプションが用意されています。

Azure CLI を使ってログ ファイルを単一の ZIP ファイルとしてダウンロードするには、コマンド プロンプト、Bash、ターミナルのいずれかのセッションを新たに開いて、次のコマンドを入力します。

az webapp log download --resource-group resourcegroupname --name functionappname

このコマンドを実行する前に、Azure portal または Azure CLI でファイル システム ログを有効にしておく必要があります。

環境変数

Functions では、サービス接続文字列などのアプリ設定は、実行中に環境変数として公開されます。 System.getenv("AzureWebJobsStorage") を使用して、これらの設定にアクセスすることができます。

次の設定では、myAppSetting という名前のキーのアプリケーション設定が取得されます。


public class Function {
    public String echo(@HttpTrigger(name = "req", methods = {HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) String req, ExecutionContext context) {
        context.getLogger().info("My app setting value: "+ System.getenv("myAppSetting"));
        return String.format(req);
    }
}

Java Functions で依存関係の挿入を使用する

Azure Functions の Java では、依存関係の挿入 (DI) ソフトウェア デザイン パターンがサポートされています。これは、クラスと依存関係の間で制御の反転 (IoC) を実現するための技術です。 Java の Azure Functions には、Functions Apps で一般的な依存関係の挿入フレームワークと統合するためのフックが用意されています。 Azure Functions の Java SPI には、インターフェイス FunctionInstanceInjector が含まれています。 このインターフェイスを実装することで、関数クラスのインスタンスを返すことができ、このインスタンスに対して関数が呼び出されます。 これにより、関数インスタンスを作成し、それを IOC コンテナーに登録する機能である SpringQuarkus、Google Guice、Dagger などのフレームワークが提供されます。 つまり、これらの依存関係の挿入フレームワークを使用して、関数を自然に管理できます。

Note

Microsoft Azure Functions の Java SPI タイプ (azure-function-java-spi) は、サード パーティが Microsoft Azure Functions のランタイムと対話するためのすべての SPI インターフェイスを含むパッケージです。

依存関係の挿入用の関数インスタンス インジェクター

azure-function-java-spi には、インターフェイス FunctionInstanceInjector が含まれています

package com.microsoft.azure.functions.spi.inject; 

/** 

 * The instance factory used by DI framework to initialize function instance. 

 * 

 * @since 1.0.0 

 */ 

public interface FunctionInstanceInjector { 

    /** 

     * This method is used by DI framework to initialize the function instance. This method takes in the customer class and returns 

     * an instance create by the DI framework, later customer functions will be invoked on this instance. 

     * @param functionClass the class that contains customer functions 

     * @param <T> customer functions class type 

     * @return the instance that will be invoked on by azure functions java worker 

     * @throws Exception any exception that is thrown by the DI framework during instance creation 

     */ 

    <T> T getInstance(Class<T> functionClass) throws Exception; 

} 

FunctionInstanceInjector を使用して依存関係の挿入フレームワークと統合するその他の例については、こちらのリポジトリを参照してください。

次のステップ

Java による Azure Functions 開発の詳細については、次のリソースを参照してください。