处理 S3 事件通知 - AWS SDK for Java 2.x

处理 S3 事件通知

为了帮助您监控存储桶中的活动,Amazon S3 可以在某些事件发生时发送通知。《Amazon S3 用户指南》提供了有关存储桶可以发送的通知的信息。

您可以使用适用于 Java 的 SDK 设置存储桶,将事件发送到四个可能的目的地:

  • Amazon Simple Notification Service 主题

  • Amazon Simple Queue Service 队列

  • AWS Lambda 函数

  • Amazon EventBridge

将存储桶设置为将事件发送到 EventBridge 时,您可以配置 EventBridge 规则以将同一事件扇出到多个目的地。将存储桶配置为直接发送到前三个目的地之一时,只能为每个事件指定一种目标类型。

在下一节中,您将了解如何使用适用于 Java 的 SDK 配置存储桶,以便通过两种方式发送 S3 事件通知:直接发送到 Amazon SQS 队列和发送到 EventBridge。

最后一部分说明了如何使用 S3 事件通知 API 来以面向对象的方式处理通知。

将存储桶配置为直接发送到目的地

以下示例将存储桶配置为在针对存储桶发生对象创建事件或对象标记事件时发送通知。

static void processS3Events(String bucketName, String queueArn) { // Configure the bucket to send Object Created and Object Tagging notifications to an existing SQS queue. s3Client.putBucketNotificationConfiguration(b -> b .notificationConfiguration(ncb -> ncb .queueConfigurations(qcb -> qcb .events(Event.S3_OBJECT_CREATED, Event.S3_OBJECT_TAGGING) .queueArn(queueArn))) .bucket(bucketName) ); }

上面显示的代码设置了一个队列来接收两种类型的事件。方便的是,queueConfigurations 方法让您可以在需要时设置多个队列目的地。此外,在 notificationConfiguration 方法中,您可以设置其他目的地,例如一个或多个 Amazon SNS 主题或一个或多个 Lambda 函数。以下代码段展示的示例中包含两个队列和三种类型的目的地。

s3Client.putBucketNotificationConfiguration(b -> b .notificationConfiguration(ncb -> ncb .queueConfigurations(qcb -> qcb .events(Event.S3_OBJECT_CREATED, Event.S3_OBJECT_TAGGING) .queueArn(queueArn), qcb2 -> qcb2.<...>) .topicConfigurations(tcb -> tcb.<...>) .lambdaFunctionConfigurations(lfcb -> lfcb.<...>)) .bucket(bucketName) );

代码示例 GitHub 存储库包含直接向队列发送 S3 事件通知的完整示例

配置要发送到 EventBridge 的存储桶

以下示例将存储桶配置为向 EventBridge 发送通知。

public static String setBucketNotificationToEventBridge(String bucketName) { // Enable bucket to emit S3 Event notifications to EventBridge. s3Client.putBucketNotificationConfiguration(b -> b .bucket(bucketName) .notificationConfiguration(b1 -> b1 .eventBridgeConfiguration(SdkBuilder::build)) .build());

将存储桶配置为向 EventBridge 发送事件时,您只需指明 EventBridge 目的地,而无需指明事件类型和 EventBridge 将分派到的最终目的地。您可以使用 Java SDK 的 EventBridge 客户端配置最终目标和事件类型。

以下代码显示如何配置 EventBridge 以将已创建对象事件扇出到主题和队列。

public static String configureEventBridge(String topicArn, String queueArn) { try { // Create an EventBridge rule to route Object Created notifications. PutRuleRequest putRuleRequest = PutRuleRequest.builder() .name(RULE_NAME) .eventPattern(""" { "source": ["aws.s3"], "detail-type": ["Object Created"], "detail": { "bucket": { "name": ["%s"] } } } """.formatted(bucketName)) .build(); // Add the rule to the default event bus. PutRuleResponse putRuleResponse = eventBridgeClient.putRule(putRuleRequest) .whenComplete((r, t) -> { if (t != null) { logger.error("Error creating event bus rule: " + t.getMessage(), t); throw new RuntimeException(t.getCause().getMessage(), t); } logger.info("Event bus rule creation request sent successfully. ARN is: {}", r.ruleArn()); }).join(); // Add the existing SNS topic and SQS queue as targets to the rule. eventBridgeClient.putTargets(b -> b .eventBusName("default") .rule(RULE_NAME) .targets(List.of ( Target.builder() .arn(queueArn) .id("Queue") .build(), Target.builder() .arn(topicArn) .id("Topic") .build()) ) ).join(); return putRuleResponse.ruleArn(); } catch (S3Exception e) { System.err.println(e.awsErrorDetails().errorMessage()); System.exit(1); } return null; }

要在 Java 代码中使用 EventBridge,请在 Maven pom.xml 文件中添加 eventbridge 构件的依赖项。

<dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>eventbridge</artifactId> </dependency>

代码示例 GitHub 存储库包含先将 S3 事件通知发送到 EventBridge,然后发送到主题和队列的完整示例

使用 S3 事件通知 API 来处理事件

目的地收到 S3 通知事件后,您可以使用 S3 事件通知 API 以面向对象的方式处理这些事件。您可以使用 S3 事件通知 API 来处理直接分派到目标的事件通知(如第一个示例所示),但不能处理通过 EventBridge 路由的通知。存储桶发送到 EventBridge 的 S3 事件通知包含不同的结构,S3 事件通知 API 当前无法处理该结构。

添加依赖项

S3 事件通知 API 随适用于 Java 的 SDK 2.x 的 2.25.11 版本一起发布。

要使用 S3 事件通知 API,请将所需的依赖项元素添加到您的 Maven pom.xml 中,如以下代码段所示。

<dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>bom</artifactId> <version>2.X.X1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>s3-event-notifications</artifactId> </dependency> </dependencies>

1 最新版本

使用 S3EventNotification

使用 JSON 字符串创建 S3EventNotification 实例

要将 JSON 字符串转换为 S3EventNotification 对象,请使用 S3EventNotification 类的静态方法,如下例所示。

import software.amazon.awssdk.eventnotifications.s3.model.S3EventNotification import software.amazon.awssdk.eventnotifications.s3.model.S3EventNotificationRecord import software.amazon.awssdk.services.sqs.model.Message; public class S3EventNotificationExample { ... void receiveMessage(Message message) { // Message received from SQSClient. String sqsEventBody = message.body(); S3EventNotification s3EventNotification = S3EventNotification.fromJson(sqsEventBody); // Use getRecords() to access all the records in the notification. List<S3EventNotificationRecord> records = s3EventNotification.getRecords(); S3EventNotificationRecord record = records.stream().findFirst(); // Use getters on the record to access individual attributes. String awsRegion = record.getAwsRegion(); String eventName = record.getEventName(); String eventSource = record.getEventSource(); } }

在此示例中,fromJson 方法将 JSON 字符串转换为 S3EventNotification 对象。JSON 字符串中缺少字段会导致相应 Java 对象字段设置为 null 值,而 JSON 中的任何多余字段则会被忽略。

事件通知记录的其他 API 可在 S3EventNotificationRecord 的 API 参考中找到。

S3EventNotification 实例转换为 JSON 字符串

使用 toJson(或 toJsonPretty)方法将 S3EventNotification 对象转换为 JSON 字符串,如下例所示。

import software.amazon.awssdk.eventnotifications.s3.model.S3EventNotification public class S3EventNotificationExample { ... void toJsonString(S3EventNotification event) { String json = event.toJson(); String jsonPretty = event.toJsonPretty(); System.out.println("JSON: " + json); System.out.println("Pretty JSON: " + jsonPretty); } }

GlacierEventDataReplicationEventDataIntelligentTieringEventDataLifecycleEventData 的字段如果为 null,则会从 JSON 中排除。其他 null 字段将序列化为 null

下面显示了 S3 对象标记事件的 toJsonPretty 方法示例输出。

{ "Records" : [ { "eventVersion" : "2.3", "eventSource" : "aws:s3", "awsRegion" : "us-east-1", "eventTime" : "2024-07-19T20:09:18.551Z", "eventName" : "ObjectTagging:Put", "userIdentity" : { "principalId" : "AWS:XXXXXXXXXXX" }, "requestParameters" : { "sourceIPAddress" : "XXX.XX.XX.XX" }, "responseElements" : { "x-amz-request-id" : "XXXXXXXXXXXX", "x-amz-id-2" : "XXXXXXXXXXXXX" }, "s3" : { "s3SchemaVersion" : "1.0", "configurationId" : "XXXXXXXXXXXXX", "bucket" : { "name" : "amzn-s3-demo-bucket", "ownerIdentity" : { "principalId" : "XXXXXXXXXXX" }, "arn" : "arn:aws:s3:::XXXXXXXXXX" }, "object" : { "key" : "akey", "size" : null, "eTag" : "XXXXXXXXXX", "versionId" : null, "sequencer" : null } } } ] }

GitHub 中提供了一个完整的示例,其中显示了如何使用 API 来处理 Amazon SQS 队列收到的通知。

使用 Java 库(AWS SDK for Java 2.x 和 aws-lambda-java-events)在 Lambda 中处理 S3 事件

您可以使用 3.x.x 版本的 aws-lambda-java-events 库,而不是使用适用于 Java 的 SDK 2.x 在 Lambda 函数中处理 Amazon S3 事件通知。AWS 单独维护 aws-lambda-java-events 库,并且它有自己的依赖项要求。aws-lambda-java-events 库仅适用于 Lambda 函数中的 S3 事件,而适用于 Java 的 SDK 2.x 可处理 Lambda 函数、Amazon SNS 和 Amazon SQS 中的 S3 事件。

两种方法都使用类似的 API 以面向对象的方式对 JSON 事件通知有效载荷建模。下表显示了使用这两种方法的显著差异。

适用于 Java 的 AWS SDK aws-lambda-java-events 库
软件包命名

software.amazon.awssdk.eventnotifications.s3.model.S3EventNotification

com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification
RequestHandler 参数

编写您的 Lambda 函数的 RequestHandler 实现以接收 JSON 字符串:

import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import software.amazon.awssdk.eventnotifications.s3.model.S3EventNotification; public class Handler implements RequestHandler<String, String> { @Override public String handleRequest(String jsonS3Event, Context context) { S3EventNotification s3Event = S3EventNotification .fromJson(jsonS3Event); // Work with the s3Event object. ... } }
编写您的 Lambda 函数的 RequestHandler 实现以接收 S3Event 对象:
import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.events.S3Event; public class Handler implements RequestHandler<S3Event, String> { @Override public String handleRequest(S3Event s3event, Context context) { // Work with the s3Event object. ... } }
Maven 依赖项
<dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>bom</artifactId> <version>2.X.X</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>s3-event-notifications</artifactId> </dependency> <!-- Add other SDK dependencies that you need. --> </dependencies>
<dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>bom</artifactId> <version>2.X.X</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <!-- The following two dependencies are for the aws-lambda-java-events library. --> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-lambda-java-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-lambda-java-events</artifactId> <version>3.15.0</version> </dependency> <!-- Add other SDK dependencies that you need. --> </dependencies>