1. 概述

本教程将深入探讨 Azure Java FunctionsAzure Function 是一种无服务器计算服务,能响应来自 Azure 服务或自定义应用的事件触发执行代码。我们可以使用 Python、PowerShell、JavaScript、C# 和 TypeScript 等语言编写事件驱动的代码。

这项特性让自动化工程师能够开发处理各类 Azure 服务事件的程序。Azure Function 提供了无服务器托管环境,无需管理基础设施即可运行代码,从而实现快速部署、自动扩展和轻松维护。

2. 高级应用场景

以下是一些 典型应用场景

Azure Function

Azure Function 是优秀的无服务器服务,擅长处理来自不同 Azure 服务或自定义应用的事件/数据。此外,我们可以配置函数按特定计划运行,从各种源轮询数据并执行后续处理。自定义应用也可通过 HTTP 协议向 Function App 发送消息。

函数能从事件上下文读取数据,进行转换或增强后发送到目标系统。事件可能是 Blob 存储容器的新文件上传、队列存储的新消息,或 Kafka 流服务中的主题。其他服务也有类似场景。

更重要的是,Azure Event Grid 服务能通过发布-订阅架构集中管理事件。服务可向 Event Grid 发布事件,订阅者应用则消费这些事件。Function App 可消费并处理来自 Event Grid 的事件

3. 核心概念

编码前需了解 Azure Functions 编程模型的几个关键概念,如绑定和触发器

部署代码到 Azure Functions 时,必须提供触发方式信息。Azure 根据这些信息调用函数——这就是触发器。**Azure Java Function 库 提供框架,通过注解声明式指定触发器**。

类似地,函数需要触发源的相关数据进行处理,这可通过输入绑定提供。当函数需要向目标系统发送数据时,输出绑定就能派上用场。与触发器不同,绑定是可选的。

假设每当 Blob Storage 上传文件时,需将其内容插入 Cosmos DB 数据库:

  • 触发器定义 Blob Storage 的文件上传事件
  • 通过触发器获取文件内容
  • 输出绑定提供目标 Cosmos DB 信息
  • 本质上它也帮助从函数返回数据

后续章节将通过实例阐明这些概念。

4. 前置要求

实际体验 Azure Function 需要:

  1. 活跃的 Azure 订阅 创建云资源
  2. 开发环境(推荐 IntelliJ + Azure Toolkit 插件

虽然插件会自动添加 Maven 依赖,但核心依赖如下:

<dependency>
    <groupId>com.microsoft.azure.functions</groupId>
    <artifactId>azure-functions-java-library</artifactId>
    <version>3.1.0</version>
</dependency>

Azure functions Maven 插件 负责打包部署:

<plugin>
    <groupId>com.microsoft.azure</groupId>
    <artifactId>azure-functions-maven-plugin</artifactId>
    <version>1.24.0</version>
</plugin>

插件配置示例(包含应用设置):

<configuration>
    <appName>${functionAppName}</appName>
    <resourceGroup>java-functions-group</resourceGroup>
    <appServicePlanName>java-functions-app-service-plan</appServicePlanName>
    <region>westus</region>
    <runtime>
        <os>windows</os>
        <javaVersion>17</javaVersion>
    </runtime>
    <appSettings>
        <property>
            <name>FUNCTIONS_EXTENSION_VERSION</name>
            <value>~4</value>
        </property>
        <property>
            <name>AZURE_STORAGE</name>
            <value>DefaultEndpointsProtocol=https;AccountName=functiondemosta;AccountKey=guymcrXX..XX;EndpointSuffix=core.windows.net</value>
        </property>
    </appSettings>
</configuration>

插件生成标准目录结构: deployment

每个触发接口生成的 function.json 定义入口点和绑定

{
  "scriptFile" : "../azure-functions-1.0.0-SNAPSHOT.jar",
  "entryPoint" : "com.baeldung.functions.BlobTriggerJava.run",
  "bindings" : [ {
    "type" : "blobTrigger",
    "direction" : "in",
    "name" : "content",
    "path" : "feeds/{name}.csv",
    "dataType" : "binary",
    "connection" : "AZURE_STORAGE"
  }, {
    "type" : "cosmosDB",
    "direction" : "out",
    "name" : "output",
    "databaseName" : "organization",
    "containerName" : "employee",
    "connection" : "COSMOS_DB"
  } ]
}

在 IntelliJ 执行 Maven 目标 clean compile package azure-functions:deploy 即可部署: azure deploy

⚠️ 部署时会自动创建/更新 Function 服务及相关资源: java-fn-group

5. Azure Function SDK 核心组件

Java 开发主要使用注解声明触发器和绑定。关键触发器包括:

  • @HttpTrigger
  • @BlobTrigger
  • @CosmosDBTrigger
  • @EventGridTrigger
  • @TimerTrigger

输入绑定注解(如 @BlobInput@CosmosDBInput)辅助函数访问事件源数据,应用于函数输入参数。

输出绑定注解(如 @BlobOutput@CosmosDBOutput)应用于 OutputBinding<T> 类型参数,用于将数据写入 Blob、Cosmos DB 等目标系统。

常用接口:

  • ExecutionContext:访问运行时环境(日志器、调用ID等)
  • HttpRequestMessage<T>:接收 HTTP 请求
  • HttpResponseMessage.Builder/HttpResponseMessage<T>:构建 HTTP 响应
  • OutputBinding<T>:输出绑定

6. Java 实现实战

6.1. HTTP 请求数据存入存储表

实现接收员工数据并写入 Azure 存储表的函数:

@FunctionName("addEmployee")
@StorageAccount("AZURE_STORAGE")
public HttpResponseMessage run(@HttpTrigger(name = "req", methods = { HttpMethod.POST }, route = "employee/{partitionKey}/{rowKey}",
  authLevel = AuthorizationLevel.FUNCTION) HttpRequestMessage<Optional<Employee>> empRequest,
  @BindingName("partitionKey") String partitionKey,
  @BindingName("rowKey") String rowKey,
  @TableOutput(name = "data", tableName = "employee") OutputBinding<Employee> employeeOutputBinding,
  final ExecutionContext context) {
    context.getLogger().info("Received a http request: " + empRequest.getBody().toString());

    Employee employee = new Employee(empRequest.getBody().get().getName(),
      empRequest.getBody().get().getDepartment(),
      empRequest.getBody().get().getSex(),
      partitionKey, rowKey);
    employeeOutputBinding.setValue(employee);

    return empRequest.createResponseBuilder(HttpStatus.OK)
      .body("Employee Inserted")
      .build();
}

客户端通过 POST 请求触发:https://{Azure Function URL}/api/employee/{partitionKey}/{rowKey}?code={function access key}
请求体为 JSON 格式员工数据,分区键和行键通过路径变量传递。@BindingName 将路径变量绑定到方法参数。

@StorageAccount 指定存储账户连接字符串(配置在应用设置中): Azure appsettings

调用示例(Postman): postman

故障排查可通过 Azure 门户查看日志: appinsight

最终数据写入存储表: azure storage table

6.2. Blob 数据迁移到 Cosmos DB

实现 Blob 文件上传自动触发函数,将数据写入 Cosmos DB

@FunctionName("BlobTriggerJava")
@StorageAccount("AZURE_STORAGE")
public void run(
  @BlobTrigger(name = "content", path = "feeds/{name}.csv", dataType = "binary") byte[] content,
  @BindingName("name") String fileName,
  @CosmosDBOutput(name = "output",
    databaseName = "organization",
    connection = "COSMOS_DB",
    containerName = "employee") OutputBinding<List<Employee>> employeeOutputBinding,
  final ExecutionContext context) {
    context.getLogger().info("Java Blob trigger function processed a blob. Name: " + fileName + "\n  Size: " + content.length + " Bytes");
    employeeOutputBinding.setValue(getEmployeeList(content));
    context.getLogger().info("Processing finished");
}

@BlobTriggerpath 属性指定监听的 Blob 文件路径。函数通过 @CosmosDBOutput 注解配置目标 Cosmos DB,连接字符串存储在环境变量 COSMOS_DB 中。

通过 IntelliJ 上传测试文件到 Blob 容器: azure explorer intellij

触发后数据写入 Cosmos DB: cosmosdb

7. 总结

本文系统介绍了 Azure Functions 的 Java 编程模型。框架设计精良且易于理解,但掌握基础故障排查技巧至关重要——当函数触发失败或无法更新目标系统时,需理解 Azure Functions 与存储账户、Application Insight 等配套服务的协作机制。

完整代码示例可在 GitHub 获取。


原始标题:Azure Functions in Java | Baeldung