使用 .zip 或 JAR 文件归档部署 Java Lambda 函数
您的 AWS Lambda 函数代码由脚本或编译的程序及其依赖项组成。您可以使用部署程序包将函数代码部署到 Lambda。Lambda 支持两种类型的部署程序包:容器镜像和 .zip 文件归档。
本页将介绍如何将部署程序包创建为 .zip 文件或 Jar 文件,然后使用该部署程序包通过 AWS Lambda (AWS Command Line Interface) 将函数代码部署到 AWS CLI。
Sections
先决条件
AWS CLI 是一种开源工具,让您能够在命令行 Shell 中使用命令与 AWS 服务进行交互。要完成本节中的步骤,您必须满足以下条件:
工具和库
Lambda 提供以下适用于 Java 函数的库:
-
com.amazonaws:aws-lambda-java-core
(必需)– 定义处理程序方法接口和运行时传递给处理程序的上下文对象。如果您定义自己的输入类型,则这是您唯一需要的库。 -
com.amazonaws:aws-lambda-java-events
– 调用 Lambda 函数服务的事件的输入类型。 -
com.amazonaws:aws-lambda-java-log4j2
– Apache Log4j 2 的 Appender 库,可用于将当前调用的请求 ID 添加到函数日志中。 -
适用于 Java 2.0 的AWS开发工具包
– 适用于 Java 编程语言的官方AWS开发工具包。
这些库可通过 Maven 中央存储库
要创建部署程序包,请将函数代码和依赖项编译成单个 .zip 文件或 Java 存档 (JAR) 文件。对于 Gradle,请使用 Zip 构建类型。对于 Apache Maven,请使用 Maven Shade 插件。要上传部署包,请使用 Lambda 控制台、Lambda API 或 AWS Serverless Application Model(AWS SAM)。
注意
为了减小部署程序包的大小,请将函数的依赖项打包到层中。层可让您独立管理依赖项,可供多个函数使用,并可与其他账户共享。有关更多信息,请参阅 使用层管理 Lambda 依赖项。
使用 Gradle 构建部署程序包
要创建包含 Gradle 中函数代码和依赖项的部署包,请使用 Zip
构建类型。这是来自完整示例 build.gradle 文件
例 build.gradle – 构建任务
task buildZip(type: Zip) { into('lib') { from(jar) from(configurations.runtimeClasspath) } }
此构建配置在 build/distributions
目录中生成部署程序包。在 into('lib')
语句中,jar
任务将包含主类的 jar 归档组装到名为 lib
的文件夹中。此外,configurations.runtimeClassPath
任务将依赖项库从构建的类路径复制到同一 lib
文件夹中。
例 build.gradle – 依赖项
dependencies { ...
implementation 'com.amazonaws:aws-lambda-java-core:1.2.2' implementation 'com.amazonaws:aws-lambda-java-events:3.11.1'
implementation 'org.apache.logging.log4j:log4j-api:2.17.1' implementation 'org.apache.logging.log4j:log4j-core:2.17.1' runtimeOnly 'org.apache.logging.log4j:log4j-slf4j18-impl:2.17.1'runtimeOnly 'com.amazonaws:aws-lambda-java-log4j2:1.5.1'
... }
Lambda 按 Unicode 字母顺序加载 JAR 文件。如果 lib
目录中的多个 JAR 文件包含相同的类,则使用第一个。可以使用以下 shell 脚本来识别重复类:
例 test-zip.sh
mkdir -p expanded unzip path/to/my/function.zip -d expanded find ./expanded/lib -name '*.jar' | xargs -n1 zipinfo -1 | grep '.*.class' | sort | uniq -c | sort
为依赖项创建 Java 层
注意
在 Java 等编译语言中将层与函数结合使用,不一定会产生与使用 Python 等解释性语言的相同效果。由于 Java 是一种编译语言,因此函数仍然需要在初始化阶段将所有共享程序集手动加载到内存中,而这可能会增加冷启动时间。我们建议您改为在编译时包含任何共享代码,以充分利用内置编译器的优化。
本部分中的说明旨在向您展示如何将依赖项包含在层中。有关如何将依赖项包含在部署包中的说明,请参阅 使用 Gradle 构建部署程序包 或 使用 Maven 构建部署程序包。
当您向函数添加层时,Lambda 会将层内容加载到该执行环境的 /opt
目录中。对于每个 Lambda 运行时系统,PATH
变量都包括 /opt
目录中的特定文件夹路径。为确保 PATH
变量能够获取层内容,层 .zip 文件应在以下文件夹路径中具有依赖项:
-
java/lib
(CLASSPATH
)
例如,层.zip 文件结构可能如下所示:
jackson.zip └ java/lib/jackson-core-2.2.3.jar
此外,Lambda 会自动检测 /opt/lib
目录中的任何库,以及 /opt/bin
目录中的任何二进制文件。为确保 Lambda 正确获取层内容,还可以创建包含以下结构的层:
custom-layer.zip └ lib | lib_1 | lib_2 └ bin | bin_1 | bin_2
打包层后,请参阅 在 Lambda 中创建和删除层 和 向函数添加层 以完成层设置。
使用 Maven 构建部署程序包
要使用 Maven 构建部署程序包,请使用 Maven Shade 插件
例 pom.xml – 插件配置
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.2</version> <configuration> <createDependencyReducedPom>false</createDependencyReducedPom> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> </execution> </executions> </plugin>
要构建部署程序包,请使用 mvn package
命令。
[INFO] Scanning for projects... [INFO] -----------------------< com.example:java-maven >----------------------- [INFO] Building java-maven-function 1.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- ... [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ java-maven --- [INFO] Building jar: target/java-maven-1.0-SNAPSHOT.jar [INFO] [INFO] --- maven-shade-plugin:3.2.2:shade (default) @ java-maven --- [INFO] Including com.amazonaws:aws-lambda-java-core:jar:1.2.2 in the shaded jar. [INFO] Including com.amazonaws:aws-lambda-java-events:jar:3.11.1 in the shaded jar. [INFO] Including joda-time:joda-time:jar:2.6 in the shaded jar. [INFO] Including com.google.code.gson:gson:jar:2.8.6 in the shaded jar. [INFO] Replacing original artifact with shaded artifact. [INFO] Replacing target/java-maven-1.0-SNAPSHOT.jar with target/java-maven-1.0-SNAPSHOT-shaded.jar [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 8.321 s [INFO] Finished at: 2020-03-03T09:07:19Z [INFO] ------------------------------------------------------------------------
此命令在 target
目录中生成 JAR 文件。
注意
如果您使用的是多版本 JAR(MRJAR)lib
目录中包含 MRJAR(即由 Maven Shade 插件生成的着色 JAR),并在将部署包上传到 Lambda 之前对其进行压缩。否则,Lambda 可能无法正确解压 JAR 文件,从而导致 MANIFEST.MF
文件被忽略。
如果您使用 Appender 库 (aws-lambda-java-log4j2
),还必须为 Maven Shade 插件配置一个转换器。转换器库合并同时出现在 Appender 库和 Log4j 中的缓存文件的版本。
例 pom.xml – 具有 Log4j 2 Appender 的插件配置
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.2</version> <configuration> <createDependencyReducedPom>false</createDependencyReducedPom> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="com.github.edwgiz.maven_shade_plugin.log4j2_cache_transformer.PluginsCacheFileTransformer"> </transformer> </transformers> </configuration> </execution> </executions> <dependencies> <dependency> <groupId>com.github.edwgiz</groupId> <artifactId>maven-shade-plugin.log4j2-cachefile-transformer</artifactId> <version>2.13.0</version> </dependency> </dependencies> </plugin>
使用 Lambda 控制台上传部署包
要创建新函数,必须先在控制台中创建该函数,然后上传您的 .zip 或 JAR 文件。要更新现有函数,请打开函数页面,然后按照相同的步骤添加更新的 .zip 或 JAR 文件。
如果您的部署包文件小于 50MB,则可以通过直接从本地计算机上传该文件来创建或更新函数。对于大于 50MB 的 .zip 或 JAR 文件,必须首先将您的程序包上传到 Amazon S3 存储桶。有关如何使用 AWS Management Console 将文件上传到 Amazon S3 存储桶的说明,请参阅 Amazon S3 入门。要使用 AWS CLI 上传文件,请参阅《AWS CLI 用户指南》中的移动对象。
注意
您无法更改现有函数的部署包类型(.zip 或容器映像)。例如,您无法将容器映像函数转换为使用 .zip 文件归档。您必须创建新函数。
创建新函数(控制台)
-
打开 Lambda 控制台的“函数”页面
,然后选择创建函数。 -
选择从头开始创作。
-
在基本信息中,执行以下操作:
-
对于函数名称,输入函数的名称。
-
对于运行时系统,选择要使用的运行时系统。
-
(可选)对于架构,选择要用于函数的指令集架构。默认架构为 x86_64。确保您的函数的 .zip 部署包与您选择的指令集架构兼容。
-
-
(可选)在 Permissions(权限)下,展开 Change default execution role(更改默认执行角色)。您可以创建新的执行角色,也可以使用现有角色。
-
选择 Create function (创建函数)。Lambda 使用您选择的运行时系统创建基本“Hello world”函数。
从本地计算机上传 .zip 或 JAR 归档(控制台)
-
在 Lambda 控制台的“函数”页面
中,选择要为其上传 .zip 或 JAR 文件的函数。 -
选择代码选项卡。
-
在代码源窗格中,选择上传自。
-
选择 .zip 或 .jar 文件。
-
要上传 .zip 或 JAR 文件,请执行以下操作:
-
选择上传,然后在文件选择器中选择您的 .zip 或 JAR 文件。
-
选择打开。
-
选择保存。
-
从 Amazon S3 存储桶上传 .zip 或 JAR 归档(控制台)
-
在 Lambda 控制台的“函数”页面
中,选择要为其上传新 .zip 或 JAR 文件的函数。 -
选择代码选项卡。
-
在代码源窗格中,选择上传自。
-
选择 Amazon S3 位置。
-
粘贴 .zip 文件的 Amazon S3 链接 URL,然后选择保存。
使用 AWS CLI 上传部署包
您可以使用 AWS CLI 创建新函数或使用 .zip 或 JAR 文件更新现有函数。使用 create-function 和 update-function-code 命令部署 .zip 或 JAR 程序包。如果您的文件小于 50MB,则可以从本地生成计算机上的文件位置上传程序包。对于较大的文件,必须从 Amazon S3 存储桶上传 .zip 或 JAR 程序包。有关如何使用 AWS CLI 将文件上传到 Amazon S3 存储桶的说明,请参阅《AWS CLI 用户指南》中的移动对象。
注意
如果您使用 AWS CLI 从 Amazon S3 存储桶上传 .zip 或 JAR 文件,则该存储桶必须与您的函数位于同一个 AWS 区域中。
要通过 AWS CLI 使用 .zip 或 JAR 文件创建新函数,则必须指定以下内容:
-
函数的名称 (
--function-name
) -
函数的运行时系统 (
--runtime
) -
函数的执行角色 (
--role
) 的 Amazon 资源名称(ARN) -
函数代码 (
--handler
) 中处理程序方法的名称
还必须指定 .zip 或 JAR 文件的位置。如果 .zip 或 JAR 文件位于本地生成计算机上的文件夹中,请使用 --zip-file
选项指定文件路径,如以下示例命令所示。
aws lambda create-function --function-name myFunction \ --runtime java21 --handler example.handler \ --role arn:aws:iam::123456789012:role/service-role/my-lambda-role \ --zip-file fileb://myFunction.zip
要指定 .zip 文件在 Amazon S3 存储桶中的位置,请使用 --code
选项,如以下示例命令所示。您只需对版本控制对象使用 S3ObjectVersion
参数。
aws lambda create-function --function-name myFunction \ --runtime java21 --handler example.handler \ --role arn:aws:iam::123456789012:role/service-role/my-lambda-role \ --code S3Bucket=amzn-s3-demo-bucket,S3Key=myFileName.zip,S3ObjectVersion=myObjectVersion
要使用 CLI 更新现有函数,请使用 --function-name
参数指定函数的名称。您还必须指定要用于更新函数代码的 .zip 文件的位置。如果 .zip 文件位于本地生成计算机上的文件夹中,请使用 --zip-file
选项指定文件路径,如以下示例命令所示。
aws lambda update-function-code --function-name myFunction \ --zip-file fileb://myFunction.zip
要指定 .zip 文件在 Amazon S3 存储桶中的位置,请使用 --s3-bucket
和 --s3-key
选项,如以下示例命令所示。您只需对版本控制对象使用 --s3-object-version
参数。
aws lambda update-function-code --function-name myFunction \ --s3-bucket amzn-s3-demo-bucket --s3-key myFileName.zip --s3-object-version myObject Version
使用 AWS SAM 上传部署程序包
您可以使用 AWS SAM 自动部署函数代码、配置和依赖项。AWS SAM 是 AWS CloudFormation 的一个扩展,它提供用于定义无服务器应用程序的简化语法。以下示例模板在 Gradle 使用的 build/distributions
目录中定义了一个包含部署程序包的函数。
例 template.yml
AWSTemplateFormatVersion: '2010-09-09' Transform: 'AWS::Serverless-2016-10-31' Description: An AWS Lambda application that calls the Lambda API. Resources: function: Type: AWS::Serverless::Function Properties:
CodeUri: build/distributions/java-basic.zip
Handler: example.Handler Runtime: java21 Description: Java function MemorySize: 512 Timeout: 10 # Function's execution role Policies: - AWSLambdaBasicExecutionRole - AWSLambda_ReadOnlyAccess - AWSXrayWriteOnlyAccess - AWSLambdaVPCAccessExecutionRole Tracing: Active
要创建函数,请使用 package
和 deploy
命令。这些命令是对 AWS CLI 的自定义。它们包装其他命令以将部署程序包上载到 Amazon S3,使用对象 URI 重写模板,然后更新函数的代码。
以下示例脚本运行 Gradle 构建并上传其创建的部署程序包。它在您第一次运行它时创建一个 AWS CloudFormation 堆栈。如果堆栈已经存在,脚本会更新它。
例 deploy.sh
#!/bin/bash set -eo pipefail aws cloudformation package --template-file template.yml --s3-bucket MY_BUCKET --output-template-file out.yml aws cloudformation deploy --template-file out.yml --stack-name java-basic --capabilities CAPABILITY_NAMED_IAM
有关完整的工作示例,请参阅以下示例应用程序。
Java 中的 Lambda 应用程序示例
-
java17-examples
:这是一种 Java 函数,演示如何使用 Java 记录来表示输入事件数据对象。 -
java-basic
– 具有单元测试和变量日志记录配置的最小 Java 函数的集合。 -
java-events
– Java 函数的集合,其中包含用于处理来自 Amazon API Gateway、Amazon SQS 和 Amazon Kinesis 等各种服务的事件的框架代码。这些函数使用最新版本的 aws-lambda-events 库(3.0.0 及更新版本)。这些示例不需要 AWS 开发工具包作为依赖项。 -
s3-java
– 此 Java 函数可处理来自 Amazon S3 的通知事件,并使用 Java 类库(JCL)从上传的图像文件创建缩略图。 -
使用 API Gateway 调用 Lambda 函数 – Java 函数,用于扫描包含员工信息的 Amazon DynamoDB 表。然后,该函数使用 Amazon Simple Notification Service 向员工发送短信,祝贺他们工作周年纪念日快乐。此示例使用 API Gateway 调用函数。