Java 中的 Amazon Lambda 函数处理程序 - Amazon Lambda
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

Java 中的 Amazon Lambda 函数处理程序

Lambda 函数处理程序是函数代码中处理事件的方法。当调用函数时,Lambda 运行处理程序方法。您的函数会一直运行,直到处理程序返回响应、退出或超时。

本指南的 GitHub repo 提供了演示各种处理程序类型的 easy-to-deploy 示例应用程序。有关详细信息,请参阅本主题的末尾

示例处理程序:Java 17 运行时系统

在如下 Java 17 示例中,名为 HandlerIntegerJava17 的类定义名为 handleRequest 的处理程序方法。处理程序方法接受以下输入:

  • IntegerRecord,即表示事件数据的自定义 Java 记录。在此示例中,我们对 IntegerRecord 进行如下定义:

    record IntegerRecord(int x, int y, String message) { }
  • 上下文对象,其提供的方法和属性包含有关调用、函数和执行环境的信息。

假设我们要编写一个函数,从输入 IntegerRecord 中记录 message 并返回 xy 的总和。函数代码如下:

HandlerIntegerJava17.java
package example; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.LambdaLogger; import com.amazonaws.services.lambda.runtime.RequestHandler; // Handler value: example.HandlerInteger public class HandlerIntegerJava17 implements RequestHandler<IntegerRecord, Integer>{ @Override /* * Takes in an InputRecord, which contains two integers and a String. * Logs the String, then returns the sum of the two Integers. */ public Integer handleRequest(IntegerRecord event, Context context) { LambdaLogger logger = context.getLogger(); logger.log("String found: " + event.message()); return event.x() + event.y(); } } record IntegerRecord(int x, int y, String message) { }

您通过在函数的配置上设置处理程序参数来指定您想要 Lambda 调用哪个方法。您可以按如下格式来表达处理程序:

  • package.Class::method – 完整格式。例如:example.Handler::handleRequest

  • package.Class:实施处理程序接口的类的缩写格式。例如:example.Handler

当 Lambda 调用您的处理程序时,Lambda 运行时系统将以 JSON 格式的字符串接收事件,并将其转换为对象。对于前述示例,示例事件可能如下:

event.json
{ "x": 1, "y": 20, "message": "Hello World!" }

您可以保存此文件并使用以下 Amazon Command Line Interface(CLI)命令在本地测试自己的函数:

aws lambda invoke --function-name function_name --payload file://event.json out.json

示例处理程序:Java 11 及以下运行时系统

Lambda 支持 Java 17 和更高版本运行时系统中的记录。在所有 Java 运行时系统中,您可以使用类来表示事件数据。以下示例将整数列表和上下文对象作为输入,并返回列表中所有整数的总和。

在以下示例中,名为 Handler 的类定义名为 handleRequest 的处理程序方法。处理程序方法接受一个事件和上下文对象作为输入并返回一个字符串。

HandlerList.java
package example; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.LambdaLogger; import com.amazonaws.services.lambda.runtime.RequestHandler; import java.util.List; // Handler value: example.HandlerList public class HandlerList implements RequestHandler<List<Integer>, Integer>{ @Override /* * Takes a list of Integers and returns its sum. */ public Integer handleRequest(List<Integer> event, Context context) { LambdaLogger logger = context.getLogger(); logger.log("EVENT TYPE: " + event.getClass().toString()); return event.stream().mapToInt(Integer::intValue).sum(); } }

如需更多示例,请参阅示例处理程序代码

初始化代码

在首次调用您的函数之前,Lambda 会在初始化阶段运行您的静态代码和类构造函数。在初始化期间创建的资源在调用之间保留在内存中,处理程序可以重复使用这些资源数千次。而后,您可以在主处理程序方法外部添加初始化代码,以便节省计算时间并跨多个调用重用资源。

在以下示例中,客户端初始化代码位于主处理程序方法之外。运行时系统会在函数提供自己的第一个事件之前初始化客户端。后续事件的提供速度则要快得多,因为 Lambda 不需要再次初始化客户端。

Handler.java
package example; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.LambdaLogger; import com.amazonaws.services.lambda.runtime.RequestHandler; import java.util.Map; import software.amazon.awssdk.services.lambda.LambdaClient; import software.amazon.awssdk.services.lambda.model.GetAccountSettingsResponse; import software.amazon.awssdk.services.lambda.model.LambdaException; // Handler value: example.Handler public class Handler implements RequestHandler<Map<String,String>, String> { private static final LambdaClient lambdaClient = LambdaClient.builder().build(); @Override public String handleRequest(Map<String,String> event, Context context) { LambdaLogger logger = context.getLogger(); logger.log("Handler invoked"); GetAccountSettingsResponse response = null; try { response = lambdaClient.getAccountSettings(); } catch(LambdaException e) { logger.log(e.getMessage()); } return response != null ? "Total code size for your account is " + response.accountLimit().totalCodeSize() + " bytes" : "Error"; } }

选择输入和输出类型

您可以在处理程序方法的签名中指定事件映射到的对象类型。在上述示例中,Java 运行时将事件反序列化为实现 Map<String,String> 接口的类型。S tring-to-string 地图适用于如下所示的平面事件:

Event.json – 天气数据
{ "temperatureK": 281, "windKmh": -3, "humidityPct": 0.55, "pressureHPa": 1020 }

但是,每个字段的值必须是字符串或数字。如果事件包含具有对象作为值的字段,则运行时无法对该字段进行反序列化并返回错误。

选择与函数处理的事件数据一起使用的输入类型。您可以使用基本类型、泛型类型或明确定义的类型。

输入类型
  • Integer LongDouble、等 – 事件是一个没有其他格式的数字(例如,3.5)。运行时将值转换为指定类型的对象。

  • String – 事件是一个 JSON 字符串,包括引号(例如,"My string.")。运行时将值(不带引号)转换为 String 对象。

  • TypeMap<String,Type> 等 – 事件是一个 JSON 对象。运行时将其反序列化为指定类型或接口的对象。

  • List<Integer> List<String>List<Object>、等 – 事件是一个 JSON 数组。运行时将其反序列化为指定类型或接口的对象。

  • InputStream – 事件是任何 JSON 类型。运行时将文档的字节流传递给处理程序而不进行修改。您可以对输入进行反序列化并将输出写到输出流。

  • 库类型-对于Amazon服务发送的事件,请使用aws-lambda-java-events库中的类型。

如果您定义了自己的输入类型,该类型应是可反序列化的、可变的普通旧 Java 对象(POJO),且事件中的每个字段都具有默认的构造函数和属性。事件中未映射到属性的键以及未包含在事件中的属性将被删除而不显示错误。

输出类型可以是对象或 void。运行时将返回值序列化为文本。如果输出是具有字段的对象,运行时会将其序列化为 JSON 文档。如果它是包装原始值的类型,则运行时返回该值的文本表示形式。

处理程序接口

aws-lambda-java-core 库为处理程序方法定义了两个接口。使用提供的接口简化处理程序配置,并在编译时验证处理程序方法签名。

RequestHandler 接口是一个泛型类型,它采用两个参数:输入类型和输出类型。这两种类型都必须是对象。使用此接口时,Java 运行时会将事件反序列化为具有输入类型的对象,并将输出序列化为文本。当内置序列化与输入和输出类型配合使用时,请使用此接口。

Handler.java – 处理程序接口
// Handler value: example.Handler public class Handler implements RequestHandler<Map<String,String>, String>{ @Override public String handleRequest(Map<String,String> event, Context context)

要使用您自己的序列化,请实现 RequestStreamHandler 接口。使用此接口,Lambda 将向您的处理程序传递输入流和输出流。处理程序从输入流读取字节,写到输出流,并返回 void。

以下示例使用缓冲读取器和写入器类型来处理输入和输出流。

HandlerStream.java
import com.amazonaws.services.lambda.runtime.Context import com.amazonaws.services.lambda.runtime.LambdaLogger import com.amazonaws.services.lambda.runtime.RequestStreamHandler ... // Handler value: example.HandlerStream public class HandlerStream implements RequestStreamHandler { @Override /* * Takes an InputStream and an OutputStream. Reads from the InputStream, * and copies all characters to the OutputStream. */ public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException { LambdaLogger logger = context.getLogger(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("US-ASCII"))); PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream, Charset.forName("US-ASCII")))); int nextChar; try { while ((nextChar = reader.read()) != -1) { outputStream.write(nextChar); } } catch (IOException e) { e.printStackTrace(); } finally { reader.close(); String finalString = writer.toString(); logger.log("Final string result: " + finalString); writer.close(); } } }

示例处理程序代码

本指南的 GitHub 存储库包括演示各种处理程序类型和接口的用法的示例应用程序。每个示例应用程序都包含用于轻松部署和清理的脚本、一个 Amazon SAM 模板和支持资源。

Java 中的 Lambda 应用程序示例
  • java17-examples:这是一种 Java 函数,演示如何使用 Java 记录来表示输入事件数据对象。

  • java-basic – 具有单元测试和变量日志记录配置的最小 Java 函数的集合。

  • java-events – Java 函数的集合,其中包含用于处理来自 Amazon API Gateway、Amazon SQS 和 Amazon Kinesis 等各种服务的事件的框架代码。这些函数使用最新版本的aws-lambda-java-events库(3.0.0 及更高版本)。这些示例不需要 Amazon 开发工具包作为依赖项。

  • s3-java – 此 Java 函数可处理来自 Amazon S3 的通知事件,并使用 Java 类库(JCL)从上传的图像文件创建缩略图。

  • 使用 API Gateway 调用 Lambda 函数 – Java 函数,用于扫描包含员工信息的 Amazon DynamoDB 表。然后,该函数使用 Amazon Simple Notification Service 向员工发送短信,祝贺他们工作周年纪念日快乐。此示例使用 API Gateway 调用函数。

java-eventss3-java 应用程序将 Amazon 服务事件作为输入并返回字符串。java-basic 应用程序包括几种类型的处理程序:

要测试不同的处理程序类型,只需更改 Amazon SAM 模板中的处理程序值即可。有关详细说明,请参阅示例应用程序的自述文件。