Azure Functions Java 开发人员指南Azure Functions Java developer guide

Azure Functions 运行时支持 Java SE 8 LTS (zulu8.31.0.2-jre8.0.181-win_x64)The Azure Functions runtime supports Java SE 8 LTS (zulu8.31.0.2-jre8.0.181-win_x64).

本指南包含有关使用 Java 编写 Azure Functions 的复杂性的信息。This guide contains information about the intricacies of writing Azure Functions with Java.

Java 函数是一个 public 方法,使用注释 @FunctionName 修饰。A Java function is a public method decorated with annotation @FunctionName. 此方法定义 java 函数的条目,必须在给定包中独一无二。This method defines the entry for a java function and must be unique in a given package.

本文假定你已阅读 Azure Functions 开发人员参考This article assumes that you have already read the Azure Functions developer reference. 此外,应该完成有关如何使用 Visual Studio Code使用 maven 创建第一个函数的 Functions 快速入门。You should also complete the Functions quickstart to create your first function, using Visual Studio Code or using maven.

编程模型Programming model

触发器和绑定是 Azure Functions 的基本概念。The concepts of triggers and bindings are fundamental to Azure Functions. 触发器启动代码的执行。Triggers start the execution of your code. 绑定可让你向函数传递数据以及从函数返回数据,而无需编写自定义的数据访问代码。Bindings give you a way to pass data to and return data from a function, without having to write custom data access code.

文件夹结构Folder structure

下面是某个 Azure Functions Java 项目的文件夹结构:Here is the folder structure of an Azure Function Java project:

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 文件,可用于配置函数应用。There's a shared host.json file that can be used to configure the function app. 每个函数都有自己的代码文件 (.java) 和绑定配置文件 (function.json)。Each function has its own code file (.java) and binding configuration file (function.json).

可在项目中放置多个函数。You can put more than one function in a project. 不要将函数放入单独的 jar 中。Avoid putting your functions into separate jars. 目标目录中的 FunctionApp 是部署到 Azure 中的函数应用的内容。The FunctionApp in the target directory is what gets deployed to your function app in Azure.

触发器和注释Triggers and annotations

Azure Functions 由触发器(例如 HTTP 请求、计时器或数据更新)进行调用。Azure functions are invoked by a trigger, such as an HTTP request, a timer, or an update to data. 函数需要处理该触发器和任何其他输入以生成一个或多个输出。Your function needs to process that trigger and any other inputs to produce one or more outputs.

使用 com.microsoft.azure.functions.annotation.* 包中附带的 Java 注释将输入和输出绑定到方法。Use the Java annotations included in the com.microsoft.azure.functions.annotation.* package to bind input and outputs to your methods. 有关详细信息,请参阅 Java 参考文档For more information see Java reference docs.

Important

必须在 local.settings.json 中配置 Azure 存储帐户,才能本地运行 Azure 存储 Blob、队列或表触发器。You must configure an Azure Storage account in your local.settings.json to run Azure Storage Blob, Queue, or Table triggers locally.

示例:Example:

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

下面是 azure-functions-maven-plugin 生成的相应 function.jsonhere is the generated corresponding function.json by the azure-functions-maven-plugin:

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

JDK 运行时可用性和支持JDK runtime availability and support

Azul Systems 下载和使用适用于 Azure 的 Azul Zulu Enterprise Java 8 JDK,以进行本地 Java 函数应用开发。Download and use the Azul Zulu Enterprise for Azure Java 8 JDKs from Azul Systems for local development of Java function apps. 将函数应用部署到云时,Azure Functions 使用 Azul Java 8 JDK 运行时。Azure Functions uses the Azul Java 8 JDK runtime when you deploy your function apps to the cloud.

对于 JDK 和函数应用的问题,Azure 支持可通过限定的支持计划获得。Azure support for issues with the JDKs and Function apps is available with a qualified support plan.

第三方库Third-party libraries

Azure Functions 支持使用第三方库。Azure Functions supports the use of third-party libraries. 默认情况下,项目 pom.xml 文件中指定的所有依赖项将在 mvn package 目标期间自动进行绑定。By default, all dependencies specified in your project pom.xml file will be automatically bundled during the mvn package goal. 对于未在 pom.xml 文件中指定为依赖项的库,请将它们放在函数根目录的 lib 目录中。For libraries not specified as dependencies in the pom.xml file, place them in a lib directory in the function's root directory. 放置在 lib 目录中的依赖项将在运行时添加到系统类加载器中。Dependencies placed in the lib directory will be added to the system class loader at runtime.

默认情况下,类路径上提供了 com.microsoft.azure.functions:azure-functions-java-library 依赖项,不需要将其包含在 lib 目录中。The com.microsoft.azure.functions:azure-functions-java-library dependency is provided on the classpath by default, and does not need to be included in the lib directory. 此外,azure-functions-java-worker 会将此处列出的依赖项添加到类路径。Also, dependencies listed here are added to the classpath by azure-functions-java-worker.

数据类型支持Data type support

可以使用无格式普通 Java 对象 (POJO)、azure-functions-java-library 中定义的类型或字符串、整数等基元 dataType 绑定到输入/输出绑定。You can use Plain old Java objects (POJOs), types defined in azure-functions-java-library or primitive dataTypes such as String, Integer to bind to input/output bindings.

普通旧 Java 对象 (POJO)Plain old Java objects (POJOs)

azure-functions-java-worker 使用 gson 库将输入数据转换为 POJO。For converting input data to POJO, azure-functions-java-worker uses gson library. 用作函数输入的 POJO 类型应是 publicPOJO types used as inputs to functions should be public.

二进制数据Binary data

通过将 function.json 中的 dataType 字段设置为 binary,将二进制输入或输出绑定到 byte[]Bind binary inputs or outputs to byte[] by setting the dataType field in your function.json to 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>Use Optional<T> for if null values are expected

绑定Bindings

输入和输出绑定提供从代码内连接到数据的声明性方式。Input and output bindings provide a declarative way to connect to data from within your code. 一个函数可以有多个输入和输出绑定。A function can have multiple input and output bindings.

示例输入绑定Example Input binding

package com.example;

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

public class Function {
    @FunctionName("echo")
    public static String echo(
        @HttpTrigger(name = "req", methods = { "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 请求调用的。This function is invoked with an HTTP request.

  • String 的形式为参数 inputReq 传递 HTTP 请求有效负载HTTP request payload is passed as a String for the argument inputReq
  • 从 Azure 表存储中检索一个项,并将其作为 TestInputData 传递给参数 inputDataOne entry is retrieved from the Azure Table Storage and is passed as TestInputData to the argument inputData.

若要接收一批输入,可以绑定到 String[]POJO[]List<String>List<POJO>To receive a batch of inputs, you can bind to String[], POJO[], List<String> or 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;
}

每当配置的事件中心内出现新数据时,就会触发此函数。This function gets triggered whenever there is new data in the configured event hub. 由于 cardinality 设置为 MANY,函数将从事件中心接收一批消息。As the cardinality is set to MANY, function receives a batch of messages from event hub. 来自事件中心的 EventData 将转换为函数执行的 TestEventDataEventData from event hub gets converted to TestEventData for the function execution.

示例输出绑定Example Output binding

可以使用 $return 将输出绑定绑定到返回值You can bind an output binding to the return value using $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;
    }
}

如果有多个输出绑定,请只使用其中一个绑定的返回值。If there are multiple output bindings, use the return value for only one of them.

若要发送多个输出值,请使用 azure-functions-java-library 包中定义的 OutputBinding<T>To send multiple output values, use OutputBinding<T> defined in the azure-functions-java-library package.

@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 调用上述函数,并将多个值写入 Azure 队列Above function is invoked on an HttpRequest and writes multiple values to the Azure Queue

HttpRequestMessage 和 HttpResponseMessageHttpRequestMessage and HttpResponseMessage

azure-functions-java-library 中定义的 HttpRequestMessage 和 HttpResponseMessage 类型是用于处理 HttpTrigger 函数的帮助器类型HttpRequestMessage and HttpResponseMessage types are defined in azure-functions-java-library are helper types to work with HttpTrigger functions

专用类型Specialized Type 目标Target 典型用途Typical Usage
HttpRequestMessage<T> HTTP 触发器HTTP Trigger 获取方法、标头或查询Get method, headers, or queries
HttpResponseMessage HTTP 输出绑定HTTP Output Binding 返回除 200 之外的状态Return status other than 200

MetadataMetadata

少量的触发器会连同输入数据一起发送触发器元数据Few triggers send trigger metadata along with input data. 可以使用注释 @BindingName 绑定到触发器元数据You can use annotation @BindingName to bind to trigger metadata

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 = { "get", "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 中的查询字符串参数 nameIn the example above, the queryValue is bound to query string parameter name in the Http request URL http://{example.host}/api/metadata?name=test. 下面是从队列触发器元数据绑定到 Id 的另一个示例Following is another example to binding to Id from queue trigger metadata

 @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

在注释中提供的名称需与元数据属性相匹配Name provided in the annotation needs to match the metadata property

执行上下文Execution context

azure-functions-java-library 中定义的 ExecutionContext 包含用来与 Functions 运行时通信的帮助器方法。ExecutionContext defined in the azure-functions-java-library contains helper methods to communicate with the functions runtime.

记录器Logger

使用 ExecutionContext 中定义的 getLogger 从函数代码写入日志。Use getLogger defined in ExecutionContext to write logs from function code.

示例:Example:


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

public class Function {
    public String echo(@HttpTrigger(name = "req", methods = {"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);
    }
}

查看日志和跟踪View logs and trace

可以使用 Azure CLI 来流式传输 Java stdout 和 stderr 日志记录以及其他应用程序日志记录。You can use the Azure CLI to stream Java stdout and stderr logging as well as other application logging.

将函数应用程序配置为使用 Azure CLI 写入应用程序日志记录:Configure your Function application to write application logging using the Azure CLI:

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

若要使用 Azure CLI 流式传输函数应用的日志记录输出,请打开新的命令行提示符、Bash 或终端会话,并输入以下命令:To stream logging output for your Function app using the Azure CLI, open a new command prompt, Bash, or Terminal session and enter the following command:

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

az webapp log tail 命令可使用 --provider 选项筛选输出。The az webapp log tail command has options to filter output using the --provider option.

若要使用 Azure CLI 下载单个 ZIP 文件形式的日志文件,请打开新的命令提示符、Bash 或终端会话,并输入以下命令:To download the log files as a single ZIP file using the Azure CLI, open a new command prompt, Bash, or Terminal session and enter the following command:

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

运行此命令之前,必须已在 Azure 门户或 Azure CLI 中启用了文件系统日志记录。You must have enabled file system logging in the Azure Portal or Azure CLI before running this command.

环境变量Environment variables

在 Functions 中,服务连接字符串等应用设置在执行过程中将公开为环境变量。In Functions, app settings, such as service connection strings, are exposed as environment variables during execution. 可以使用 System.getenv("AzureWebJobsStorage") 访问这些设置You can access these settings using, System.getenv("AzureWebJobsStorage")

示例:Example:

添加名为 testAppSetting、值为 testAppSettingValue 的 AppSettingAdd AppSetting with name testAppSetting and value testAppSettingValue


public class Function {
    public String echo(@HttpTrigger(name = "req", methods = {"post"}, authLevel = AuthorizationLevel.ANONYMOUS) String req, ExecutionContext context) {
        context.getLogger().info("testAppSetting "+ System.getenv("testAppSettingValue"));
        return String.format(req);
    }
}

后续步骤Next steps

有关 Azure 函数 Java 开发的详细信息,请参阅以下资源:For more information about Azure Function Java development, see the following resources: