Microsoft Azure Functions

适用于 Spring Cloud Function 应用程序作为本机 Azure Java 函数的 Azure 函数适配器。 Azure 函数编程模型广泛依赖 Java 注释,用于定义函数的处理程序方法及其输入和输出类型。在编译时,已提供 Azure Maven/Gradle 插件来处理带注释的类,以生成必要的 Azure 函数绑定文件、配置和包工件。Azure 注释只是一种类型安全的方式,用于将您的 Java 函数配置为被识别为 Azure 函数。 spring-cloud-function-adapter-azure 扩展了基本编程模型,以提供 Spring 和 Spring Cloud Function 支持。借助此适配器,您可以使用依赖注入功能构建 Spring Cloud Function 应用程序,然后将必要的服务自动注入 Azure 处理程序方法。 image::{github-raw}/docs/src/main/asciidoc/images/scf-azure-adapter.svg[]

对于基于 Web 的函数应用程序,您可以使用专门的 spring-cloud-function-adapter-azure-web 替换通用的 adapter-azure。使用 Azure Web 适配器,您可以将任何 Spring Web 应用程序部署为 Azure HttpTrigger 函数。此适配器隐藏了 Azure 注解的复杂性,而使用熟悉的 Spring Web 编程模型替换了它们。有关更多信息,请参见下面的 Azure Web Adapter 部分。

Azure Adapter

为 Azure 函数提供 Spring 和 Spring Cloud Function 集成。

Dependencies

为了启用 Azure 函数集成,请将 Azure 适配器依赖项添加到 pom.xmlbuild.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 Worker 集成。

Development Guidelines

使用 @Component (或 @Service)注释将任何退出的 Azure Function 类(例如使用 @FunctionName 处理程序)转换为 Spring 组件。然后,您可以自动装配所需的依赖项(或 Spring Cloud Function 组合的 Function Catalog),并在 Azure 函数处理程序中使用它们。

@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());
	}
}
1 指出 MyAzureFunction 类是 Spring Framework 作为自动检测和类路径扫描的候选者考虑的“组件”。
2 自动关联在 HttpTriggerDemoApplication (如下所示)中定义的 uppercasefunctionCatalog Bean。
3 @FunctionName 注释标识指定的 Azure 函数处理程序。当由触发器(如 @HttpTrigger)调用时,函数会处理该触发器和任何其他输入,以生成一个或多个输出。
4 plainBean 方法处理程序被映射到 Azure 函数,该函数使用自动关联的 uppercase spring bean 来计算结果。它演示了如何在 Azure 处理程序中使用“普通”Spring 组件。
5 springCloudFunction 方法处理程序被映射到另一个 Azure 函数,该函数使用自动关联的 FunctionCatalog 实例来计算结果。
6 展示如何利用 Spring Cloud Function Function Catalog 组合 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,如 main class configuration 中所述。
2 函数在 Azure 函数处理程序中自动关联并使用。

Function Catalog

Spring Cloud Function 支持一系列用户定义函数的类型签名,同时提供一致的执行模型。为此,它使用 Function Catalog 将所有用户定义的函数转换成规范表示形式。

Azure 适配器可以自动连接任何 Spring 组件,例如上面的 uppercase。不过这些组件被视为普通 Java 类实例,而不是规范的 Spring Cloud Functions!

若要利用 Spring Cloud Function 并访问规范化的函数表示,您需要自动连接 FunctionCatalog 并将其用在处理程序中,例如上面 springCloudFunction() 处理程序中的 functionCatalog 实例。

Accessing Azure ExecutionContext

有时需要以 com.microsoft.azure.functions.ExecutionContext 的形式访问 Azure 运行时提供的目标执行上下文。例如,这些需求之一便是日志记录,以便在 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);
}
1 利用 AzureFunctionUtil 实用工具来使用 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 实例。

Configuration

若要在 Microsoft Azure 上运行函数应用程序,您必须提供必要的配置,例如 function.jsonhost.json,并遵照必需的格式打包。

通常,Azure Maven(或 Gradle)插件用于从带注释的类生成必要的配置并生成所需的 package 格式。

Azure packaging format 与默认的 Spring Boot 包装(例如 uber jar)不兼容。下面的 Disable Spring Boot Plugin 部分说明如何处理此问题。

[[azure-maven/gradle-plugins]]=== Azure Maven/Gradle 插件

Azure 提供的 maven 及 gradle 插件用于处理带注释的类、生成必要的配置以及生成预期的 package 布局。插件用于设置平台、运行时和应用程序设置属性,如下所示:

  • 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 版本,部署的操作系统。

Disable Spring Boot Plugin

可以预料,Azure 函数在 Azure 执行运行时内部运行,而不是在 Spring Boot 运行时内部运行!此外,Azure 期望 Azure Maven/Gradle 插件生成的特定打包格式与默认的 Spring Boot 打包不兼容。

您必须禁用 Spring Boot Maven/Gradle 插件或按照以下 Maven 片段中的说明使用 Spring Boot Thin Launcher:

<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 Configuration

指定 Main-Class/Start-Class 指向 Spring 应用程序入口点,例如上面示例中的 HttpTriggerDemoApplication 类。

您可以使用 Maven 的 start-class 属性或设置 MANIFEST/META-INFOMain-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 门户部署,请在 App Settings 中设置该变量。

如果没有设置 MAIN_CLASS 变量,Azure 适配器将从在类路径上找到的 jar 中查找 MANIFEST/META-INFO 属性,并选择第一个通过 @SpringBootApplication@SpringBootConfiguration 注释标记的 Main-Class:

Metadata Configuration

您可以使用共享的 host.json 文件来配置函数应用程序。

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

host.json 元数据文件包含影响函数应用程序实例中所有函数的配置选项。

如果文件不在项目顶级文件夹中,则需要相应地配置你的插件(如 hostJson maven 属性)。

Samples

以下是您可以探索的各种 Spring Cloud Function Azure 适配器示例:

Azure Web Adapter

对于纯粹基于 Web 的函数应用程序,您可以用专门的 spring-cloud-function-adapter-azure-web 替换通用的 adapter-azure。Azure Web 适配器可以使用 HttpTrigger 在内部部署任何 Spring Web 应用程序作为本机 Azure 函数。它隐藏了 Azure 注释的复杂性,而是依赖于熟悉的 Spring Web 编程模型。

若要启用 Azure Web 适配器,请向您的 pom.xmlbuild.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'
}

相同的 ConfigurationUsage 指令也适用于 Azure Web Adapter

Azure Samples

有关详细信息,请探索以下内容(Azure Web 适配器)示例:

Usage

用于构建和部署“Azure 适配器”和“Azure Web 适配器”类型应用程序的通用说明。

Build

  • Maven

  • Gradle

./mvnw -U clean package
./gradlew azureFunctionsPackage

Running locally

若要在 `Azure Functions`之上本地运行并部署到您的实时 Azure 环境,您需要安装 `Azure Functions Core Tools`以及 Azure CLI(见 here)。对于某些配置,您还需要 Azurite emulator

然后运行示例:

  • Maven

  • Gradle

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

Running on Azure

确保您已登录您的 Azure 帐户。

az login

并部署

  • Maven

  • Gradle

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

Debug locally

在调试模式下运行函数。

  • 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"
}

或者,将 JAVA_OPTS 值设为 local.settings.json,如下所示:

{
	"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 (deprecated)

旧的 FunctionInvoker 编程模型已弃用,并且将来将不受支持。

有关函数集成方法的其他文档和示例,请按照 azure-sample中的自述文件和代码进行操作。