Microsoft Azure Functions

Spring Cloud Function アプリケーションをネイティブ Azure Java 関数としてデプロイするための Azure (英語) 関数アダプター。

Azure Functions  プログラミングモデル (英語) は、関数のハンドラーメソッドとその入出力型を定義するための Java アノテーション (英語) を広範囲に中継します。コンパイル時に、アノテーション付きクラスは提供された Azure Maven/Gradle プラグインによって処理され、必要な Azure Function バインディングファイル、構成、パッケージアーティファクトが生成されます。Azure アノテーションは、java 関数が Azure function として認識されるように構成する型 セーフな方法にすぎません。

spring-cloud-function-adapter-azure [GitHub] (英語) は、基本的なプログラミングモデルを継承して、Spring および Spring Cloud Function のサポートを提供します。アダプターを使用すると、依存関係の注入を使用して Spring Cloud Function アプリケーションを構築し、必要なサービスを Azure ハンドラーメソッドに自動接続できます。

scf azure adapter
Web ベースの関数アプリケーションの場合、汎用 adapter-azure を特殊な spring-cloud-function-adapter-azure-web [GitHub] (英語) に置き換えることができます。Azure Web アダプターを使用すると、任意の Spring Web アプリケーションを Azure、HttpTrigger 関数としてデプロイできます。このアダプターは、Azure アノテーションの複雑さを隠し、代わりに使い慣れた Spring Web プログラミングモデルを使用します。詳細については、以下の Azure Web アダプターセクションを参照してください。

Azure アダプター

Azure Functions に Spring および Spring Cloud Function の統合を提供します。

依存関係

Azure Function 統合を有効にするには、Azure アダプターの依存関係を pom.xml または build.gradle ファイルに追加します。

  • Maven

  • Gradle

<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-function-adapter-azure</artifactId>
	</dependency>
</dependencies>
dependencies {
    implementation 'org.springframework.cloud:spring-cloud-function-adapter-azure'
}
バージョン 4.0.0+ が必要です。アダプターをクラスパス上に置くと、Azure Java ワーカー 統合がアクティブ化されます。

開発ガイドライン

@Component (または @Service) アノテーションを使用して、既存の Azure Function クラス (@FunctionName ハンドラーなど) を Spring コンポーネントに変換します。その後、必要な依存関係 (または Spring Cloud Function 構成の関数カタログ ) を自動接続し、Azure function ハンドラー内で使用できます。

@Component (1)
public class MyAzureFunction {

	// Plain Spring bean - not a Spring Cloud Functions!
	@Autowired private Function<String, String> uppercase; (2)

	// The FunctionCatalog leverages the Spring Cloud Function framework.
	@Autowired private FunctionCatalog functionCatalog; (2)

	@FunctionName("spring") (3)
	public String plainBean( (4)
			@HttpTrigger(name = "req",
				methods = { HttpMethod.POST },
				authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
				ExecutionContext context) {

		return this.uppercase.apply(request.getBody().get());
	}

	@FunctionName("scf") (3)
	public String springCloudFunction( (5)
			@HttpTrigger(name = "req",
			methods = { HttpMethod.POST },
			authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
			ExecutionContext context) {

		// Use SCF composition. Composed functions are not just spring beans but SCF such.
		Function composed = this.functionCatalog.lookup("reverse|uppercase"); (6)

		return (String) composed.apply(request.getBody().get());
	}
}
1MyAzureFunction クラスが、Spring Framework によって自動検出およびクラスパススキャンの候補として考慮される「コンポーネント」であることを示します。
2HttpTriggerDemoApplication で定義された uppercase Bean と functionCatalog Bean を自動接続します (下記)。
3@FunctionName (英語) アノテーションは、指定された Azure function ハンドラーを識別します。トリガー ( @HttpTrigger など) によって呼び出されると、関数はそのトリガーおよびその他の入力を処理して 1 つ以上の出力を生成します。
4plainBean メソッドハンドラーは、オートワイヤーされた uppercase Spring Bean を使用して結果を計算する Azure function にマップされます。Azure ハンドラーで「プレーン」Spring コンポーネントを使用する方法を示します。
5springCloudFunction メソッドハンドラーは別の Azure function にマップされ、自動接続された FunctionCatalog インスタンスを使用して結果を計算します。
6Spring Cloud Function 関数カタログ合成 API を活用する方法を示します。
com.microsoft.azure.functions.annotation.* (英語) パッケージに含まれる Java アノテーションを使用して、入力と出力をメソッドにバインドします。

Azure ハンドラー内で使用されるビジネスロジックの実装は、一般的な Spring アプリケーションと似ています。

@SpringBootApplication (1)
public class HttpTriggerDemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(HttpTriggerDemoApplication.class, args);
	}

	@Bean
	public Function<String, String> uppercase() { (2)
		return payload -> payload.toUpperCase();
	}

	@Bean
	public Function<String, String> reverse() { (2)
		return payload -> new StringBuilder(payload).reverse().toString();
	}
}
1 メインクラスの設定で説明したように、@SpringBootApplication アノテーション付きクラスは Main-Class として使用されます。
2 関数はオートワイヤーされ、Azure function ハンドラーで使用されます。

関数カタログ

Spring Cloud Function は、一貫した実行モデルを提供しながら、ユーザー定義関数のさまざまな型シグネチャーをサポートします。このために、関数カタログを使用して、すべてのユーザー定義関数を正規表現に変換します。

Azure アダプターは、上記の uppercase などの Spring コンポーネントをオートワイヤーできます。ただし、これらは正規の Spring Cloud 関数としてではなく、プレーンな Java クラスインスタンスとして扱われます。

Spring Cloud Function を利用して正規関数表現にアクセスするには、FunctionCatalog をオートワイヤーし、上記の functionCatalog インスタンスや springCloudFunction() ハンドラーと同様に、それをハンドラーで使用する必要があります。

Azure へのアクセス ExecutionContext

Azure ランタイムによって com.microsoft.azure.functions.ExecutionContext の形式で提供されるターゲット実行コンテキストにアクセスする必要がある場合があります。たとえば、そのようなニーズの 1 つはロギングであるため、Azure コンソールに表示できます。

その目的のために、AzureFunctionUtil.enhanceInputIfNecessary を使用すると、ExecutionContext のインスタンスをメッセージヘッダーとして追加できるため、executionContext キーを介して取得できます。

@FunctionName("myfunction")
public String execute(
	@HttpTrigger(name = "req",
		methods = { HttpMethod.POST },
		authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
		ExecutionContext context) {

	Message message =
		(Message) AzureFunctionUtil.enhanceInputIfNecessary(request.getBody().get(), context); (1)

	return this.uppercase.apply(message);
}
1AzureFunctionUtil ユーティリティを利用して、AzureFunctionUtil.EXECUTION_CONTEXT ヘッダーキーを使用して context をメッセージヘッダーとしてインライン化します。

これで、メッセージヘッダーから ExecutionContext を取得できるようになりました。

@Bean
public Function<Message<String>, String> uppercase(JsonMapper mapper) {
	return message -> {
		String value = message.getPayload();
		ExecutionContext context =
			(ExecutionContext) message.getHeaders().get(AzureFunctionUtil.EXECUTION_CONTEXT); (1)
		. . .
	}
}
1 ヘッダーから ExecutionContext インスタンスを取得します。

構成

Microsoft Azure で関数アプリケーションを実行するには、function.json や host.json などの必要な構成を提供し、必須のパッケージ化形式 (英語) に従う必要があります。

通常、Azure Maven (または Gradle) プラグインは、アノテーション付きクラスから必要な構成を生成し、必要なパッケージ形式を生成するために使用されます。

Azure パッケージ形式 (英語) は、デフォルトの Spring Boot パッケージ (例: uber jar) と互換性がありません。以下の Spring Boot プラグインを無効にするセクションでは、これに対処する方法について説明します。

[[azure-maven/gradle-plugins]] === Azure Maven/Gradle プラグイン

Azure は、アノテーション付きクラスを処理し、必要な構成を生成し、期待されるパッケージレイアウトを生成するための Maven [GitHub] (英語) および Gradle [GitHub] (英語) プラグインを提供します。プラグインは、次のようにプラットフォーム、ランタイム、アプリ設定のプロパティを設定するために使用されます。

  • Maven

  • Gradle

<plugin>
	<groupId>com.microsoft.azure</groupId>
	<artifactId>azure-functions-maven-plugin</artifactId>
	<version>1.22.0 or higher</version>

	<configuration>
		<appName>YOUR-AZURE-FUNCTION-APP-NAME</appName>
		<resourceGroup>YOUR-AZURE-FUNCTION-RESOURCE-GROUP</resourceGroup>
		<region>YOUR-AZURE-FUNCTION-APP-REGION</region>
		<appServicePlanName>YOUR-AZURE-FUNCTION-APP-SERVICE-PLANE-NAME</appServicePlanName>
		<pricingTier>YOUR-AZURE-FUNCTION-PRICING-TIER</pricingTier>

		<hostJson>${project.basedir}/src/main/resources/host.json</hostJson>

		<runtime>
			<os>linux</os>
			<javaVersion>11</javaVersion>
		</runtime>

		<appSettings>
			<property>
				<name>FUNCTIONS_EXTENSION_VERSION</name>
				<value>~4</value>
			</property>
		</appSettings>
	</configuration>
	<executions>
		<execution>
			<id>package-functions</id>
			<goals>
				<goal>package</goal>
			</goals>
		</execution>
	</executions>
</plugin>
plugins {
    id "com.microsoft.azure.azurefunctions" version "1.11.0"
	// ...
}

apply plugin: "com.microsoft.azure.azurefunctions"

azurefunctions {
	appName = 'YOUR-AZURE-FUNCTION-APP-NAME'
    resourceGroup = 'YOUR-AZURE-FUNCTION-RESOURCE-GROUP'
    region = 'YOUR-AZURE-FUNCTION-APP-REGION'
    appServicePlanName = 'YOUR-AZURE-FUNCTION-APP-SERVICE-PLANE-NAME'
    pricingTier = 'YOUR-AZURE-FUNCTION-APP-SERVICE-PLANE-NAME'

    runtime {
      os = 'linux'
      javaVersion = '11'
    }

    auth {
      type = 'azure_cli'
    }

    appSettings {
      FUNCTIONS_EXTENSION_VERSION = '~4'
    }
	// Uncomment to enable local debug
    // localDebug = "transport=dt_socket,server=y,suspend=n,address=5005"
}

ランタイム構成の詳細については、Java バージョン (英語) デプロイ OS (英語) を参照してください。

Spring Boot プラグインを無効にする

予想どおり、Azure Functions は SpringBoot ランタイム内ではなく、Azure 実行ランタイム内で実行されます。さらに、Azure は、Azure Maven/Gradle プラグインによって生成される、デフォルトの Spring Boot パッケージ化と互換性のない特定のパッケージ化形式を想定しています。

SpringBoot Maven/Gradle プラグインを無効にするか、次の Maven スニペットに示すように Spring Boot シンランチャー [GitHub] (英語) を使用する必要があります。

<plugin>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-maven-plugin</artifactId>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot.experimental</groupId>
			<artifactId>spring-boot-thin-layout</artifactId>
		</dependency>
	</dependencies>
</plugin>

メインクラスの構成

Main-Class/Start-Class を指定して、Spring アプリケーションエントリポイント (上の例の HttpTriggerDemoApplication クラスなど) を指します。

Maven start-class プロパティを使用するか、MANIFEST/META-INFO の Main-Class 属性を設定できます。

  • Maven

  • Gradle

<properties>
	<start-class>YOUR APP MAIN CLASS</start-class>
	...
</properties>
jar {
    manifest {
        attributes(
            "Main-Class": "YOUR-APP-MAIN-CLASS"
        )
    }
}
あるいは、MAIN_CLASS 環境変数を使用してクラス名を明示的に設定することもできます。ローカル実行の場合は、MAIN_CLASS 変数を local.settings.json ファイルに追加し、Azure ポータルデプロイ の場合はアプリの設定 (英語) に変数を設定します。
MAIN_CLASS 変数が設定されていない場合、Azure アダプターはクラスパス上で見つかった jar から MANIFEST/META-INFO 属性を検索し、@SpringBootApplication または @SpringBootConfiguration アノテーションのいずれかが付けられた最初の Main-Class: を選択します。

メタデータの構成

共有 host.json (英語) ファイルを使用して関数アプリを構成できます。

{
	"version": "2.0",
	"extensionBundle": {
		"id": "Microsoft.Azure.Functions.ExtensionBundle",
		"version": "[4.*, 5.0.0)"
	}
}

host.json メタデータファイルには、関数アプリインスタンス内のすべての関数に影響を与える構成オプションが含まれています。

ファイルがプロジェクトのトップフォルダーにない場合は、それに応じてプラグインを設定する必要があります (hostJson maven 属性など)。

Azure Web アダプター

純粋な Web ベースの関数アプリケーションの場合は、汎用 adapter-azure を特殊な spring-cloud-function-adapter-azure-web [GitHub] (英語) に置き換えることができます。Azure Web アダプターは、内部で HttpTrigger を使用して、任意の Spring Web アプリケーションをネイティブ Azure function としてデプロイできます。Azure アノテーションの複雑さを隠し、代わりに使い慣れた Spring Web プログラミングモデルに依存します。

Azure Web アダプターを有効にするには、アダプターの依存関係を pom.xml または build.gradle ファイルに追加します。

  • Maven

  • Gradle

<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-function-adapter-azure-web</artifactId>
	</dependency>
</dependencies>
dependencies {
    implementation 'org.springframework.cloud:spring-cloud-function-adapter-azure-web'
}

同じ構成および使用方法命令が Azure Web Adapter にも適用されます。

Azure サンプル

詳細については、Azure Web アダプターのサンプルを参照してください。

使用方法

Azure Adapter 型と Azure Web Adapter タイプのアプリケーションの両方を構築およびデプロイするための共通の手順。

ビルド

  • Maven

  • Gradle

./mvnw -U clean package
./gradlew azureFunctionsPackage

ローカルで実行

Azure Functions 上でローカルに実行し、ライブ Azure 環境にデプロイするには、Azure CLI と共に Azure Functions Core Tools をインストールする必要があります ( こちら を参照)。構成によっては、アズライトエミュレーター (英語) も必要になる場合があります。

次に、サンプルを実行します。

  • Maven

  • Gradle

./mvnw azure-functions:run
./gradlew azureFunctionsRun

Azure で実行

Azure アカウントにログインしていることを確認してください。

az login

そしてデプロイ

  • Maven

  • Gradle

./mvnw azure-functions:deploy
./gradlew azureFunctionsDeploy

ローカルでデバッグする

関数をデバッグモードで実行します。

  • Maven

  • Gradle

./mvnw azure-functions:run -DenableDebug
// If you want to debug your functions, please add the following line
// to the azurefunctions section of your build.gradle.
azurefunctions {
  ...
  localDebug = "transport=dt_socket,server=y,suspend=n,address=5005"
}

別の方法として、次のように local.settings.json に JAVA_OPTS の値を指定します。

{
	"IsEncrypted": false,
	"Values": {
		...
		"FUNCTIONS_WORKER_RUNTIME": "java",
		"JAVA_OPTS": "-Djava.net.preferIPv4Stack=true -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=127.0.0.1:5005"
	}
}

VSCode リモートデバッグ構成のスニペットを次に示します。

{
	"version": "0.2.0",
	"configurations": [
		{
			"type": "java",
			"name": "Attach to Remote Program",
			"request": "attach",
			"hostName": "localhost",
			"port": "5005"
		},
	]
}

FunctionInvoker (非推奨)

従来の FunctionInvoker プログラミングモデルは非推奨となり、今後はサポートされなくなります。

関数統合アプローチに関する追加のドキュメントとサンプルについては、azure-sample [GitHub] (英語) README とコードに従ってください。