Microsoft Azure Functions

用于将 Spring Cloud Function 应用部署为原生 Azure Java Functions 的 Azure 函数适配器。

Azure Functions 编程模型广泛依赖 Java 注解来定义函数的处理方法及其输入和输出类型。在编译时,提供的 Azure Maven/Gradle 插件会处理带注解的类,以生成必要的 Azure Function 绑定文件、配置和打包 artifacts。Azure 注解只是一种类型安全的方式,用于配置您的 Java 函数使其被识别为 Azure 函数。

spring-cloud-function-adapter-azure 扩展了基本编程模型,以提供对 Spring 和 Spring Cloud Function 的支持。通过此适配器,您可以使用依赖注入构建您的 Spring Cloud Function 应用,然后将必要的服务自动装配到您的 Azure handler 方法中。

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

Azure 适配器

为 Azure Functions 提供 SpringSpring Cloud Function 集成。

依赖项

为了启用 Azure Function 集成,请将 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+。在 classpath 中包含此适配器会激活 Azure Java Worker 集成。

开发指南

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

@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 在自动检测和 classpath 扫描时考虑的“组件”。
2 自动装配 HttpTriggerDemoApplication(如下所示)中定义的 uppercasefunctionCatalog bean。
3 @FunctionName 注解标识指定的 Azure 函数 handler。当由 trigger(例如 @HttpTrigger)调用时,函数会处理该 trigger 以及任何其他输入,以产生一个或多个输出。
4 plainBean 方法 handler 映射到一个 Azure 函数,该函数使用自动装配的 uppercase Spring bean 计算结果。这演示了如何在 Azure handler 中使用“普通”Spring 组件。
5 springCloudFunction 方法 handler 映射到另一个 Azure 函数,该函数使用自动装配的 FunctionCatalog 实例计算结果。
6 展示了如何利用 Spring Cloud Function Function Catalog 组合 API。
使用 com.microsoft.azure.functions.annotation.* 包中包含的 Java 注解来将输入和输出绑定到您的方法。

Azure handler 中使用的业务逻辑实现看起来像一个普通的 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 函数 handler 中自动装配和使用的函数。

Function Catalog

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

Azure 适配器可以自动装配任何 Spring 组件,例如上面提到的 uppercase。但它们被视为普通的 Java 类实例,而不是规范的 Spring Cloud Functions!

要利用 Spring Cloud Function 并访问规范函数表示,您需要在 handler 中自动装配 FunctionCatalog 并使用它,就像上面 springCloudFunction() handler 中的 functionCatalog 实例一样。

访问 Azure ExecutionContext

有时需要访问 Azure 运行时提供的目标执行上下文,其形式为 com.microsoft.azure.functions.ExecutionContext。例如,其中一个需求是日志记录,以便它能显示在 Azure 控制台中。

为此,AzureFunctionUtil.enhanceInputIfNecessary 允许您将 ExecutionContext 实例添加为 Message header,以便您可以通过 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 header 键将 context 内联为 message header。

现在您可以从 message header 中检索 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 从 header 中检索 ExecutionContext 实例。

配置

要在 Microsoft Azure 上运行您的函数应用,您必须提供必要的配置,例如 function.jsonhost.json,并遵循强制性的打包格式

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

Azure 打包格式与默认的 Spring Boot 打包(例如 uber jar)不兼容。禁用 Spring Boot 插件部分解释了如何处理这个问题。

Azure Maven/Gradle 插件

Azure 提供了 MavenGradle 插件,用于处理带注解的类、生成必要的配置并生成预期的包布局。插件用于设置平台、运行时和应用设置属性,如下所示

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

禁用 Spring Boot 插件

正如预期,Azure Functions 运行在 Azure 执行时中,而不是 SpringBoot 执行时中!此外,Azure 需要由 Azure Maven/Gradle 插件生成的特定打包格式,该格式与默认的 Spring Boot 打包不兼容。

您必须禁用 SpringBoot Maven/Gradle 插件或使用 Spring Boot Thin Launcher,如下面的 Maven 片段所示

<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 配置

指定 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 门户部署,在应用设置中设置该变量。
如果未设置 MAIN_CLASS 变量,Azure 适配器将查找 classpath 中找到的 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 属性)。

示例

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

Azure Web 适配器

对于纯粹基于 Web 的函数应用,您可以用专门的 spring-cloud-function-adapter-azure-web 替换通用的 adapter-azure。Azure Web 适配器可以作为原生 Azure 函数部署任何 Spring Web 应用,内部使用 HttpTrigger。它隐藏了 Azure 注解的复杂性,而是依赖于熟悉的 Spring Web 编程模型。更多信息请参阅下面的 Azure 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'
}

相同的配置使用方法说明也适用于 Azure Web 适配器

Azure 示例

更多信息请探索以下 Azure Web 适配器示例

使用方法

构建和部署 Azure 适配器和 Azure Web 适配器类型应用的通用说明。

构建

  • Maven

  • Gradle

./mvnw -U clean package
./gradlew azureFunctionsPackage

本地运行

要在 Azure Functions 上本地运行并部署到您的实时 Azure 环境,您需要安装 Azure Functions Core Tools 和 Azure CLI(参见此处)。对于某些配置,您还需要 Azurite 模拟器

然后运行示例

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

或者将 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 (已弃用)

遗留的 FunctionInvoker 编程模型已弃用,将来将不再支持。

有关函数集成方法的更多文档和示例,请参阅 azure-sample 的 README 和代码。