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

使用 Java Lambda 函数的层

Lambda 层是包含补充代码或数据的 .zip 文件存档。层通常包含库依赖项、自定义运行时系统或配置文件。创建层涉及三个常见步骤:

  1. 打包层内容。此步骤需要创建 .zip 文件存档,其中包含要在函数中使用的依赖项。

  2. 在 Lambda 中创建层。

  3. 将层添加到函数。

本主题包含有关如何正确打包并创建具有外部库依赖项的 Java Lambda 层的步骤和指南。

先决条件

要完成本部分中的步骤,您必须满足以下条件:

注意

确保 Maven 引用的 Java 版本与要部署的函数的 Java 版本相同。例如,若要部署 Java 21 函数,mvn -v 命令应在输出中列出 Java 版本 21:

Apache Maven 3.8.6 ... Java version: 21.0.2, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/jdk-21.jdk/Contents/Home ...

在整个主题中,我们会引用 awsdocs GitHub 存储库中的 layer-java 示例应用程序。该应用程序包含用于下载依赖项并生成层的脚本。该应用程序还包含相应的函数,函数使用来自层的依赖项。创建层后,即可部署并调用相应的函数来验证一切是否正常运行。由于使用 Java 21 运行时系统来运行这些函数,因此这些层还必须与 Java 21 兼容。

layer-java 示例应用程序在两个子目录中包含一个示例。layer 目录包含用于定义层依赖项的 pom.xml 文件,以及用于生成层的脚本。function 目录包含示例函数,用于帮助测试该层是否正常工作。本教程将演示如何创建并打包该层。

Java 层与 Amazon Linux 的兼容性

创建层的第一步是将所有层内容捆绑到.zip 文件存档中。由于 Lambda 函数在 Amazon Linux 上运行,因此层内容必须能够在 Linux 环境中编译和构建。

Java 代码采用独立于平台的设计,即便本地计算机不使用 Linux 环境,您也可以在本地计算机上打包层。将 Java 层上传到 Lambda 后,Java 层仍将与 Amazon Linux 兼容。

Java 运行时系统的层路径

当您向函数添加层时,Lambda 会将层内容加载到该执行环境的 /opt 目录中。对于每个 Lambda 运行时系统,PATH 变量都包括 /opt 目录中的特定文件夹路径。为确保 PATH 变量能够获取层内容,层 .zip 文件应在以下文件夹路径中具有依赖项:

  • java/lib

例如,您在本教程中创建生成的层.zip 文件具有以下目录结构:

layer_content.zip └ java └ lib └ layer-java-layer-1.0-SNAPSHOT.jar

layer-java-layer-1.0-SNAPSHOT.jar JAR 文件(包含所有必需依赖项的 uber-jar)位于 java/lib 目录中,位置正确。这可确保 Lambda 在函数调用期间可以找到该库。

打包层内容

本示例将以下两个 Java 库打包到单个 JAR 文件中:

  • aws-lambda-java-core:一组在 Amazon Lambda 中用于处理 Java 的最小接口定义

  • Jackson:一套特别适用于处理 JSON 的热门数据处理工具。

完成以下步骤,安装并打包层内容。

安装并打包层内容
  1. 克隆 aws-lambda-developer-guide GitHub 存储库,其中包含 sample-apps/layer-java 目录中需要的示例代码。

    git clone https://github.com/awsdocs/aws-lambda-developer-guide.git
  2. 导航到 layer-java 示例应用程序的 layer 目录。此目录包含用于正确创建并打包层的脚本。

    cd aws-lambda-developer-guide/sample-apps/layer-java/layer
  3. 检查 pom.xml 文件。在 <dependencies> 部分,定义要包含在层中的依赖项,即 aws-lambda-java-corejackson-databind 库。您可以更新此文件,纳入要包含在层中的任何依赖项。

    例 pom.xml
    <dependencies> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-lambda-java-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.17.0</version> </dependency> </dependencies>
    注意

    pom.xml 文件的 <build> 部分包含两个插件。maven-compiler-plugin 可编译源代码。maven-shade-plugin 可将构件打包到一个 uber-jar 中。

  4. 确保拥有运行这两个脚本的权限。

    chmod 744 1-install.sh && chmod 744 2-package.sh
  5. 使用以下命令运行 1-install.sh 脚本:

    ./1-install.sh

    此脚本在当前目录中运行 mvn clean install。这会在 target/ 目录中创建包含所有必需依赖项的 uber-jar。

    例 1-install.sh
    mvn clean install
  6. 使用以下命令运行 2-package.sh 脚本:

    ./2-package.sh

    此脚本会创建正确打包层内容所需的 java/lib 目录结构。然后,其会将 uber-jar 从 /target 目录复制到新创建的 java/lib 目录中。最后,此脚本会将 java 目录的内容压缩到名为 layer_content.zip 的文件中。这便是层的 .zip 文件。您可以解压缩文件,验证是否包含正确的文件结构,如 Java 运行时系统的层路径部分所示。

    例 2-package.sh
    mkdir java mkdir java/lib cp -r target/layer-java-layer-1.0-SNAPSHOT.jar java/lib/ zip -r layer_content.zip java

创建层

在本部分,您会获取在上一部分中生成的 layer_content.zip 文件,将其作为 Lambda 层上传。您可以使用 Amazon Web Services Management Console 上传层,也可以通过 Amazon Command Line Interface(Amazon CLI)使用 Lambda API 上传层。上传层 .zip 文件时,在以下 PublishLayerVersion Amazon CLI 命令中,将 java21 指定为兼容的运行时系统,并将 arm64 指定为兼容的架构。

aws lambda publish-layer-version --layer-name java-jackson-layer \ --zip-file fileb://layer_content.zip \ --compatible-runtimes java21 \ --compatible-architectures "arm64"

注意响应中的 LayerVersionArn,与 arn:aws:lambda:us-east-1:123456789012:layer:java-jackson-layer:1 类似。在本教程的下一步中,在将层添加到函数时,您要用到此 Amazon 资源名称(ARN)。

将层添加到函数

在本部分,您要部署在函数代码中使用 Jackson 库的示例 Lambda 函数,然后附加该层。要部署该函数,您需要一个 Lambda 执行角色。如果目前没有执行角色,则按照可折叠部分中的步骤操作。若有,则跳至下一部分来部署函数。

创建执行角色
  1. 在 IAM 控制台中,打开 Roles(角色)页面

  2. 选择创建角色

  3. 创建具有以下属性的角色。

    • Trusted entity(可信任的实体)– Lambda

    • Permissions(权限)– AWSLambdaBasicExecutionRole

    • Role name(角色名称)– lambda-role

    AWSLambdaBasicExecutionRole 策略具有函数将日志写入 CloudWatch Logs 所需的权限。

部署 Lambda 函数
  1. 导航到 function/ 目录。如果当前在 layer/ 目录中,请运行以下命令:

    cd ../function
  2. 检查函数代码。函数接受 Map<String, String> 作为输入,并使用 Jackson 将输入写为 JSON 字符串,然后再将其转换为预定义的 F1Car Java 对象。最后,函数使用 F1Car 对象中的字段来构造函数返回的字符串。

    package example; import com.amazonaws.services.lambda.runtime.Context; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.util.Map; public class Handler { public String handleRequest(Map<String, String> input, Context context) throws IOException { // Parse the input JSON ObjectMapper objectMapper = new ObjectMapper(); F1Car f1Car = objectMapper.readValue(objectMapper.writeValueAsString(input), F1Car.class); StringBuilder finalString = new StringBuilder(); finalString.append(f1Car.getDriver()); finalString.append(" is a driver for team "); finalString.append(f1Car.getTeam()); return finalString.toString(); } }
  3. 使用以下 Maven 命令构建项目:

    mvn package

    此命令在名为 layer-java-function-1.0-SNAPSHOT.jartarget/ 目录中生成 JAR 文件。

  4. 部署函数。在以下 Amazon CLI 命令中,将 --role 参数替换为执行角色 ARN:

    aws lambda create-function --function-name java_function_with_layer \ --runtime java21 \ --architectures "arm64" \ --handler example.Handler::handleRequest \ --timeout 30 \ --role arn:aws:iam::123456789012:role/lambda-role \ --zip-file fileb://target/layer-java-function-1.0-SNAPSHOT.jar

此时,可以选择在附加层之前尝试调用函数。如果尝试该操作,之后应会收到 ClassNotFoundException,因为函数无法引用 requests 程序包。要调用函数,请使用以下 Amazon CLI 命令:

aws lambda invoke --function-name java_function_with_layer \ --cli-binary-format raw-in-base64-out \ --payload '{ "driver": "Max Verstappen", "team": "Red Bull" }' response.json

应看到类似如下内容的输出:

{ "StatusCode": 200, "FunctionError": "Unhandled", "ExecutedVersion": "$LATEST" }

要查看特定错误,请打开输出 response.json 文件。您会看到包含以下错误消息的 ClassNotFoundException

"errorMessage":"com.fasterxml.jackson.databind.ObjectMapper","errorType":"java.lang.ClassNotFoundException"

接下来,将层附加到函数。在以下 Amazon CLI 命令中,将 --layers 参数替换为之前记下的层版本 ARN:

aws lambda update-function-configuration --function-name java_function_with_layer \ --cli-binary-format raw-in-base64-out \ --layers "arn:aws:lambda:us-east-1:123456789012:layer:java-jackson-layer:1"

最后,尝试使用以下 Amazon CLI 命令调用函数:

aws lambda invoke --function-name java_function_with_layer \ --cli-binary-format raw-in-base64-out \ --payload '{ "driver": "Max Verstappen", "team": "Red Bull" }' response.json

应看到类似如下内容的输出:

{ "StatusCode": 200, "ExecutedVersion": "$LATEST" }

这表示函数能够使用 Jackson 依赖项来正确执行函数。您可以检查输出 response.json 文件是否包含正确的返回字符串:

"Max Verstappen is a driver for team Red Bull"

除非您想要保留为本教程创建的资源,否则可立即将其删除。通过删除您不再使用的 Amazon 资源,可防止您的 Amazon Web Services 账户 产生不必要的费用。

删除 Lambda 层
  1. 打开 Lambda 控制台的 Layers page(层页面)。

  2. 选择您创建的层。

  3. 选择删除,然后再次选择删除

删除 Lambda 函数
  1. 打开 Lamba 控制台的 Functions(函数)页面

  2. 选择您创建的函数。

  3. 依次选择操作删除

  4. 在文本输入字段中键入 delete,然后选择 Delete(删除)。