AWS CDK 构造 - AWS Cloud Development Kit (AWS CDK) v2

这是 AWS CDK v2 开发者指南。较旧的 CDK v1 于 2022 年 6 月 1 日进入维护阶段,并于 2023 年 6 月 1 日终止支持。

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

AWS CDK 构造

构造是 AWS Cloud Development Kit (AWS CDK) 应用程序的基本构建基块。构造是应用程序中的一个组件,它代表一个或多个 AWS CloudFormation 资源及其配置。您可以通过导入和配置构造逐步构建应用程序。

导入和使用构造

构造是您从 AWS 构造库中导入到 CDK 应用程序中的类。您也可以创建和分发自己的构造,或者使用第三方开发人员创建的构造。

构造是构造编程模型(CPM)的一部分。它们可以与其他工具搭配使用,例如 CDK for Terraform(CDKtf)、CDK for Kubernetes(CDK8s)和 Projen。

许多第三方也发布了与 AWS CDK 兼容的构造。访问 Construct Hub,探索 AWS CDK 构造合作伙伴生态系统。

构造级别

AWS 构造库中的构造分为三个级别。每个级别都提供不断提高的抽象级别。抽象越高,配置越容易,所需的专业知识也越少。抽象越低,可用的自定义越多,需要更多的专业知识。

级别 1(L1)构造

L1 构造,也称为 CFN 资源,是最低级别的构造,不提供抽象。每个 L1 构造都直接映射到单个 AWS CloudFormation 资源。通过 L1 构造,您可以导入代表特定 AWS CloudFormation 资源的构造。然后,您可以在构造实例中定义资源的属性。

当您熟悉 AWS CloudFormation 并需要完全控制 AWS 资源属性的定义时,L1 构造非常适用。

在 AWS 构造库中,L1 构造的名称以 Cfn 开头,后跟它所代表的 AWS CloudFormation 资源的标识符。例如,CfnBucket 构造是代表 AWS::S3::Bucket AWS CloudFormation 资源的 L1 构造。

L1 构造是由 AWS CloudFormation 资源规范生成的。如果资源存在于 AWS CloudFormation 中,则该资源将作为 L1 构造在 AWS CDK 中可用。新资源或属性可能需要长达一周的时间才能在 AWS 构造库中可用。有关更多信息,请参阅《AWS CloudFormation 用户指南》中的 AWS 资源和属性类型参考

级别 2(L2)构造

L2 构造,也称为精选构造,由 CDK 团队精心开发,通常是使用最广泛的构造类型。与 L1 构造类似,L2 构造直接映射到单个 AWS CloudFormation 资源。与 L1 构造相比,L2 构造通过直观的基于意图的 API 提供更高级别的抽象。L2 构造包括合理的默认属性配置、最佳实践安全策略,并为您生成大量样板代码和粘合逻辑。

L2 构造还为大多数资源提供助手方法,使定义属性、权限、资源之间基于事件的交互等变得更加简单快捷。

s3.Bucket 类是 Amazon Simple Storage Service(Amazon S3)存储桶资源的 L2 构造示例。

AWS 构造库包含指定为稳定且可用于生产环境的 L2 构造。对于正在开发的 L2 构造,它们被指定为实验性质,并在单独的模块中提供。

级别 3(L3)构造

L3 构造,也称为模式,是最高级别的抽象。每个 L3 构造可以包含一组资源,这些资源配置为协同工作以完成应用程序中的特定任务或服务。L3 构造可用于为应用程序中的特定用例创建整个 AWS 架构。

为了提供完整的系统设计或大型系统的重要组成部分,L3 构造可提供有主见的默认属性配置。它们围绕旨在解决问题和提供解决方案的特定方法而构建。通过 L3 构造,您可以用最少的输入和代码快速创建和配置多个资源。

ecsPatterns.ApplicationLoadBalancedFargateService 类是 L3 构造的示例,该构造代表在 Amazon Elastic Container Service(Amazon ECS)集群上运行并以应用程序负载均衡器为前端的 AWS Fargate 服务。

与 L2 构造类似,可用于生产环境的 L3 构造包含在 AWS 构造库中。正在开发的此类构造以单独的模块提供。

定义构造

合成

合成是通过构造定义更高级别抽象的关键模式。高级构造可以由任意数量的较低级别的构造合成。从自下而上的角度来看,您可以使用构造组织要部署的单个 AWS 资源。您可以根据自身需求使用任何抽象和任意数量的级别。

通过合成,您可以定义可重用的组件,并像共享任何其他代码一样共享它们。例如,团队可以定义一种构造,用于实现公司对 Amazon DynamoDB 表的最佳实践,包括备份、全局复制、自动扩缩和监控。团队可以在内部与其他团队共享构造,也可以公开共享。

团队可以像使用任何其他库包一样使用构造。与任何其他代码库类似,库更新后,开发人员可以访问新版本的改进和错误修复。

初始化

构造是在扩展 Construct 基类的类中实现的。您可以通过实例化类定义构造。所有构造在初始化时都有三个参数:

  • 作用域:构造的父级或所有者。这可以是堆栈或其他构造。作用域决定构造在构造树中的位置。通常,您必须传递 this(在 Python 中传递 self),它表示当前对象为作用域。

  • id:在此作用域内必须唯一的标识符。该标识符用作构造中定义的所有内容的命名空间。它可用于生成唯一标识符,例如资源名称和 AWS CloudFormation 逻辑 ID。

    标识符只需要在作用域内唯一。这使您可以实例化和重用构造,而不必担心它们可能包含的构造和标识符,并且可以将构造组合成更高级别的抽象。此外,通过作用域,一次性引用一组构造成为可能。示例包括标记或指定将构造部署到的位置。

  • props:定义构造的初始配置的一组属性或关键字参数,视语言而定。更高级别的构造可提供更多的默认值,如果所有 prop 元素都是可选的,则可以完全省略 props 参数。

配置

大多数构造都接受 props 作为其第三个参数(Python:关键字参数),这是一种定义构造配置的名称/值集合。以下示例定义了一个启用了 AWS Key Management Service(AWS KMS)加密和静态网站托管的存储桶。由于它没有显式指定加密密钥,因此 Bucket 构造会定义一个新的 kms.Key 并将其与存储桶相关联。

TypeScript
new s3.Bucket(this, 'MyEncryptedBucket', { encryption: s3.BucketEncryption.KMS, websiteIndexDocument: 'index.html' });
JavaScript
new s3.Bucket(this, 'MyEncryptedBucket', { encryption: s3.BucketEncryption.KMS, websiteIndexDocument: 'index.html' });
Python
s3.Bucket(self, "MyEncryptedBucket", encryption=s3.BucketEncryption.KMS, website_index_document="index.html")
Java
Bucket.Builder.create(this, "MyEncryptedBucket") .encryption(BucketEncryption.KMS_MANAGED) .websiteIndexDocument("index.html").build();
C#
new Bucket(this, "MyEncryptedBucket", new BucketProps { Encryption = BucketEncryption.KMS_MANAGED, WebsiteIndexDocument = "index.html" });
Go
awss3.NewBucket(stack, jsii.String("MyEncryptedBucket"), &awss3.BucketProps{ Encryption: awss3.BucketEncryption_KMS, WebsiteIndexDocument: jsii.String("index.html"), })

与构造互动

构造是在扩展 Construct 基类的类中实现的。实例化构造后,构造对象会公开一组方法和属性,供您用于与该构造进行交互并将其作为对系统其他部分的引用传递。

AWS CDK 框架对构造的 API 没有任何限制。作者可以定义他们想要的任何 API。但是,AWS 构造库中包含的 AWS 构造(例如 s3.Bucket)遵循准则和常见模式。这为所有 AWS 资源提供了一致的体验。

大多数 AWS 构造都有一组 grant 方法,您可以使用这些方法向主体授予对该构造的 AWS Identity and Access Management(IAM)权限。以下示例会向 IAM 组 data-science 授予从 Amazon S3 存储桶 raw-data 中读取数据的权限。

TypeScript
const rawData = new s3.Bucket(this, 'raw-data'); const dataScience = new iam.Group(this, 'data-science'); rawData.grantRead(dataScience);
JavaScript
const rawData = new s3.Bucket(this, 'raw-data'); const dataScience = new iam.Group(this, 'data-science'); rawData.grantRead(dataScience);
Python
raw_data = s3.Bucket(self, 'raw-data') data_science = iam.Group(self, 'data-science') raw_data.grant_read(data_science)
Java
Bucket rawData = new Bucket(this, "raw-data"); Group dataScience = new Group(this, "data-science"); rawData.grantRead(dataScience);
C#
var rawData = new Bucket(this, "raw-data"); var dataScience = new Group(this, "data-science"); rawData.GrantRead(dataScience);
Go
rawData := awss3.NewBucket(stack, jsii.String("raw-data"), nil) dataScience := awsiam.NewGroup(stack, jsii.String("data-science"), nil) rawData.GrantRead(dataScience, nil)

另一种常见的模式是 AWS 构造根据其他地方提供的数据设置资源的其中一项属性。属性可能包括 Amazon 资源名称(ARN)、名称或 URL。

以下代码定义了 AWS Lambda 函数,并通过环境变量中的队列 URL 将其与 Amazon Simple Queueue Service(Amazon SQS)队列关联。

TypeScript
const jobsQueue = new sqs.Queue(this, 'jobs'); const createJobLambda = new lambda.Function(this, 'create-job', { runtime: lambda.Runtime.NODEJS_18_X, handler: 'index.handler', code: lambda.Code.fromAsset('./create-job-lambda-code'), environment: { QUEUE_URL: jobsQueue.queueUrl } });
JavaScript
const jobsQueue = new sqs.Queue(this, 'jobs'); const createJobLambda = new lambda.Function(this, 'create-job', { runtime: lambda.Runtime.NODEJS_18_X, handler: 'index.handler', code: lambda.Code.fromAsset('./create-job-lambda-code'), environment: { QUEUE_URL: jobsQueue.queueUrl } });
Python
jobs_queue = sqs.Queue(self, "jobs") create_job_lambda = lambda_.Function(self, "create-job", runtime=lambda_.Runtime.NODEJS_18_X, handler="index.handler", code=lambda_.Code.from_asset("./create-job-lambda-code"), environment=dict( QUEUE_URL=jobs_queue.queue_url ) )
Java
final Queue jobsQueue = new Queue(this, "jobs"); Function createJobLambda = Function.Builder.create(this, "create-job") .handler("index.handler") .code(Code.fromAsset("./create-job-lambda-code")) .environment(java.util.Map.of( // Map.of is Java 9 or later "QUEUE_URL", jobsQueue.getQueueUrl()) .build();
C#
var jobsQueue = new Queue(this, "jobs"); var createJobLambda = new Function(this, "create-job", new FunctionProps { Runtime = Runtime.NODEJS_18_X, Handler = "index.handler", Code = Code.FromAsset(@".\create-job-lambda-code"), Environment = new Dictionary<string, string> { ["QUEUE_URL"] = jobsQueue.QueueUrl } });
Go
createJobLambda := awslambda.NewFunction(stack, jsii.String("create-job"), &awslambda.FunctionProps{ Runtime: awslambda.Runtime_NODEJS_18_X(), Handler: jsii.String("index.handler"), Code: awslambda.Code_FromAsset(jsii.String(".\\create-job-lambda-code"), nil), Environment: &map[string]*string{ "QUEUE_URL": jsii.String(*jobsQueue.QueueUrl()), }, })

有关 AWS 构造库中最常见 API 模式的信息,请参阅资源和 AWS CDK

应用程序和堆栈构造

AWS 构造库中的 AppStack 类是唯一的构造。与其他构造相比,这两类不会自行配置 AWS 资源。但可用于为其他构造提供上下文。所有代表 AWS 资源的构造必须在 Stack 构造的作用域内直接或间接地定义。Stack 构造在 App 构造的作用域内定义。

要了解有关 CDK 应用程序的更多信息,请参阅 AWS CDK 应用程序。要了解有关 CDK 堆栈的更多信息,请参阅 AWS CDK 堆栈简介

以下示例会定义具有单个堆栈的应用程序。在堆栈中,L2 构造可用于配置 Amazon S3 存储桶资源。

TypeScript
import { App, Stack, StackProps } from 'aws-cdk-lib'; import * as s3 from 'aws-cdk-lib/aws-s3'; class HelloCdkStack extends Stack { constructor(scope: App, id: string, props?: StackProps) { super(scope, id, props); new s3.Bucket(this, 'MyFirstBucket', { versioned: true }); } } const app = new App(); new HelloCdkStack(app, "HelloCdkStack");
JavaScript
const { App , Stack } = require('aws-cdk-lib'); const s3 = require('aws-cdk-lib/aws-s3'); class HelloCdkStack extends Stack { constructor(scope, id, props) { super(scope, id, props); new s3.Bucket(this, 'MyFirstBucket', { versioned: true }); } } const app = new App(); new HelloCdkStack(app, "HelloCdkStack");
Python
from aws_cdk import App, Stack import aws_cdk.aws_s3 as s3 from constructs import Construct class HelloCdkStack(Stack): def __init__(self, scope: Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) s3.Bucket(self, "MyFirstBucket", versioned=True) app = App() HelloCdkStack(app, "HelloCdkStack")
Java

HelloCdkStack.java 文件中定义的堆栈:

import software.constructs.Construct; import software.amazon.awscdk.Stack; import software.amazon.awscdk.StackProps; import software.amazon.awscdk.services.s3.*; public class HelloCdkStack extends Stack { public HelloCdkStack(final Construct scope, final String id) { this(scope, id, null); } public HelloCdkStack(final Construct scope, final String id, final StackProps props) { super(scope, id, props); Bucket.Builder.create(this, "MyFirstBucket") .versioned(true).build(); } }

HelloCdkApp.java 文件中定义的应用程序:

import software.amazon.awscdk.App; import software.amazon.awscdk.StackProps; public class HelloCdkApp { public static void main(final String[] args) { App app = new App(); new HelloCdkStack(app, "HelloCdkStack", StackProps.builder() .build()); app.synth(); } }
C#
using Amazon.CDK; using Amazon.CDK.AWS.S3; namespace HelloCdkApp { internal static class Program { public static void Main(string[] args) { var app = new App(); new HelloCdkStack(app, "HelloCdkStack"); app.Synth(); } } public class HelloCdkStack : Stack { public HelloCdkStack(Construct scope, string id, IStackProps props=null) : base(scope, id, props) { new Bucket(this, "MyFirstBucket", new BucketProps { Versioned = true }); } } }
Go
func NewHelloCdkStack(scope constructs.Construct, id string, props *HelloCdkStackProps) awscdk.Stack { var sprops awscdk.StackProps if props != nil { sprops = props.StackProps } stack := awscdk.NewStack(scope, &id, &sprops) awss3.NewBucket(stack, jsii.String("MyFirstBucket"), &awss3.BucketProps{ Versioned: jsii.Bool(true), }) return stack }

使用构造

使用 L1 构造

L1 构造直接映射到单个 AWS CloudFormation 资源。您必须提供资源所需的配置。

在本例中,我们使用 CfnBucket L1 构造创建一个 bucket 对象:

TypeScript
const bucket = new s3.CfnBucket(this, "amzn-s3-demo-bucket", { bucketName: "amzn-s3-demo-bucket" });
JavaScript
const bucket = new s3.CfnBucket(this, "amzn-s3-demo-bucket", { bucketName: "amzn-s3-demo-bucket" });
Python
bucket = s3.CfnBucket(self, "amzn-s3-demo-bucket", bucket_name="amzn-s3-demo-bucket")
Java
CfnBucket bucket = new CfnBucket.Builder().bucketName("amzn-s3-demo-bucket").build();
C#
var bucket = new CfnBucket(this, "amzn-s3-demo-bucket", new CfnBucketProps { BucketName= "amzn-s3-demo-bucket" });
Go
awss3.NewCfnBucket(stack, jsii.String("amzn-s3-demo-bucket"), &awss3.CfnBucketProps{ BucketName: jsii.String("amzn-s3-demo-bucket"), })

不是简单布尔值、字符串、数字或容器的构造属性在受支持的语言中的处理方式有所不同。

TypeScript
const bucket = new s3.CfnBucket(this, "amzn-s3-demo-bucket", { bucketName: "amzn-s3-demo-bucket", corsConfiguration: { corsRules: [{ allowedOrigins: ["*"], allowedMethods: ["GET"] }] } });
JavaScript
const bucket = new s3.CfnBucket(this, "amzn-s3-demo-bucket", { bucketName: "amzn-s3-demo-bucket", corsConfiguration: { corsRules: [{ allowedOrigins: ["*"], allowedMethods: ["GET"] }] } });
Python

在 Python 中,这些属性由定义为 L1 构造内部类的类型表示。例如,CfnBucket 的可选属性 cors_configuration 需要一个 CfnBucket.CorsConfigurationProperty 类型的封装器。在本例中,我们将在一个 CfnBucket 实例上定义 cors_configuration

bucket = CfnBucket(self, "amzn-s3-demo-bucket", bucket_name="amzn-s3-demo-bucket", cors_configuration=CfnBucket.CorsConfigurationProperty( cors_rules=[CfnBucket.CorsRuleProperty( allowed_origins=["*"], allowed_methods=["GET"] )] ) )
Java

在 Java 中,这些属性由定义为 L1 构造内部类的类型表示。例如,CfnBucket 的可选属性 corsConfiguration 需要一个 CfnBucket.CorsConfigurationProperty 类型的封装器。在本例中,我们将在一个 CfnBucket 实例上定义 corsConfiguration

CfnBucket bucket = CfnBucket.Builder.create(this, "amzn-s3-demo-bucket") .bucketName("amzn-s3-demo-bucket") .corsConfiguration(new CfnBucket.CorsConfigurationProperty.Builder() .corsRules(Arrays.asList(new CfnBucket.CorsRuleProperty.Builder() .allowedOrigins(Arrays.asList("*")) .allowedMethods(Arrays.asList("GET")) .build())) .build()) .build();
C#

在 C# 中,这些属性由定义为 L1 构造内部类的类型表示。例如,CfnBucket 的可选属性 CorsConfiguration 需要一个 CfnBucket.CorsConfigurationProperty 类型的封装器。在本例中,我们将在一个 CfnBucket 实例上定义 CorsConfiguration

var bucket = new CfnBucket(this, "amzn-s3-demo-bucket", new CfnBucketProps { BucketName = "amzn-s3-demo-bucket", CorsConfiguration = new CfnBucket.CorsConfigurationProperty { CorsRules = new object[] { new CfnBucket.CorsRuleProperty { AllowedOrigins = new string[] { "*" }, AllowedMethods = new string[] { "GET" }, } } } });
Go

在 Go 中,这些类型是使用 L1 构造的名称、下划线和属性名称命名的。例如,CfnBucket 的可选属性 CorsConfiguration 需要一个 CfnBucket_CorsConfigurationProperty 类型的封装器。在本例中,我们将在一个 CfnBucket 实例上定义 CorsConfiguration

awss3.NewCfnBucket(stack, jsii.String("amzn-s3-demo-bucket"), &awss3.CfnBucketProps{ BucketName: jsii.String("amzn-s3-demo-bucket"), CorsConfiguration: &awss3.CfnBucket_CorsConfigurationProperty{ CorsRules: []awss3.CorsRule{ awss3.CorsRule{ AllowedOrigins: jsii.Strings("*"), AllowedMethods: &[]awss3.HttpMethods{"GET"}, }, }, }, })
重要

您不能将 L2 属性类型与 L1 构造一起使用,反之亦然。使用 L1 构造时,请务必使用为正在使用的 L1 构造定义的类型。请勿使用其他 L1 构造中的类型(有些可能具有相同的名称,但类型不同)。

目前,一些特定于语言的 API 引用在指向 L1 属性类型的路径中存在错误,或者根本没有记录这些类。我们希望尽快解决这个问题。同时,请记住,这些类型始终是与之一起使用的 L1 构造的内部类。

使用 L2 构造

在以下示例中,我们通过从 Bucket L2 构造中创建对象来定义 Amazon S3 存储桶:

TypeScript
import * as s3 from 'aws-cdk-lib/aws-s3'; // "this" is HelloCdkStack new s3.Bucket(this, 'MyFirstBucket', { versioned: true });
JavaScript
const s3 = require('aws-cdk-lib/aws-s3'); // "this" is HelloCdkStack new s3.Bucket(this, 'MyFirstBucket', { versioned: true });
Python
import aws_cdk.aws_s3 as s3 # "self" is HelloCdkStack s3.Bucket(self, "MyFirstBucket", versioned=True)
Java
import software.amazon.awscdk.services.s3.*; public class HelloCdkStack extends Stack { public HelloCdkStack(final Construct scope, final String id) { this(scope, id, null); } public HelloCdkStack(final Construct scope, final String id, final StackProps props) { super(scope, id, props); Bucket.Builder.create(this, "MyFirstBucket") .versioned(true).build(); } }
C#
using Amazon.CDK.AWS.S3; // "this" is HelloCdkStack new Bucket(this, "MyFirstBucket", new BucketProps { Versioned = true });
Go
import ( "github.com/aws/aws-cdk-go/awscdk/v2/awss3" "github.com/aws/jsii-runtime-go" ) // stack is HelloCdkStack awss3.NewBucket(stack, jsii.String("MyFirstBucket"), &awss3.BucketProps{ Versioned: jsii.Bool(true), })>

MyFirstBucket 不是 AWS CloudFormation 创建的存储桶的名称。它是在 CDK 应用程序的上下文中赋予新构造的逻辑标识符。physicalName 值将用于命名 AWS CloudFormation 资源。

使用第三方构造

您可以使用 Construct Hub 发现来自 AWS、第三方和开源 CDK 社区的其他构造。

编写自己的构造

除了使用现有构造之外,您还可以编写自己的构造,让任何人在其应用程序中使用。AWS CDK 中的所有构造都是平等的。AWS 构造库中的构造与通过 NPM、Maven 或 PyPI 发布的第三方库中的构造将按相同方式处理。发布到公司内部包存储库的构造也将按相同方式处理。

要声明新构造,请在 constructs 包中创建一个扩展 Construct 基类的类,然后遵循初始化程序参数的模式。

以下示例展示了如何声明代表 Amazon S3 存储桶的构造。每当有用户向 S3 存储桶中上传文件时,该存储桶都会发送 Amazon Simple Notification Service(Amazon SNS)通知。

TypeScript
export interface NotifyingBucketProps { prefix?: string; } export class NotifyingBucket extends Construct { constructor(scope: Construct, id: string, props: NotifyingBucketProps = {}) { super(scope, id); const bucket = new s3.Bucket(this, 'bucket'); const topic = new sns.Topic(this, 'topic'); bucket.addObjectCreatedNotification(new s3notify.SnsDestination(topic), { prefix: props.prefix }); } }
JavaScript
class NotifyingBucket extends Construct { constructor(scope, id, props = {}) { super(scope, id); const bucket = new s3.Bucket(this, 'bucket'); const topic = new sns.Topic(this, 'topic'); bucket.addObjectCreatedNotification(new s3notify.SnsDestination(topic), { prefix: props.prefix }); } } module.exports = { NotifyingBucket }
Python
class NotifyingBucket(Construct): def __init__(self, scope: Construct, id: str, *, prefix=None): super().__init__(scope, id) bucket = s3.Bucket(self, "bucket") topic = sns.Topic(self, "topic") bucket.add_object_created_notification(s3notify.SnsDestination(topic), s3.NotificationKeyFilter(prefix=prefix))
Java
public class NotifyingBucket extends Construct { public NotifyingBucket(final Construct scope, final String id) { this(scope, id, null, null); } public NotifyingBucket(final Construct scope, final String id, final BucketProps props) { this(scope, id, props, null); } public NotifyingBucket(final Construct scope, final String id, final String prefix) { this(scope, id, null, prefix); } public NotifyingBucket(final Construct scope, final String id, final BucketProps props, final String prefix) { super(scope, id); Bucket bucket = new Bucket(this, "bucket"); Topic topic = new Topic(this, "topic"); if (prefix != null) bucket.addObjectCreatedNotification(new SnsDestination(topic), NotificationKeyFilter.builder().prefix(prefix).build()); } }
C#
public class NotifyingBucketProps : BucketProps { public string Prefix { get; set; } } public class NotifyingBucket : Construct { public NotifyingBucket(Construct scope, string id, NotifyingBucketProps props = null) : base(scope, id) { var bucket = new Bucket(this, "bucket"); var topic = new Topic(this, "topic"); bucket.AddObjectCreatedNotification(new SnsDestination(topic), new NotificationKeyFilter { Prefix = props?.Prefix }); } }
Go
type NotifyingBucketProps struct { awss3.BucketProps Prefix *string } func NewNotifyingBucket(scope constructs.Construct, id *string, props *NotifyingBucketProps) awss3.Bucket { var bucket awss3.Bucket if props == nil { bucket = awss3.NewBucket(scope, jsii.String(*id+"Bucket"), nil) } else { bucket = awss3.NewBucket(scope, jsii.String(*id+"Bucket"), &props.BucketProps) } topic := awssns.NewTopic(scope, jsii.String(*id+"Topic"), nil) if props == nil { bucket.AddObjectCreatedNotification(awss3notifications.NewSnsDestination(topic)) } else { bucket.AddObjectCreatedNotification(awss3notifications.NewSnsDestination(topic), &awss3.NotificationKeyFilter{ Prefix: props.Prefix, }) } return bucket }
注意

NotifyingBucket 构造不是继承自 Bucket,而是继承自 Construct。我们使用组合而不是继承,以将 Amazon S3 存储桶和 Amazon SNS 主题捆绑在一起。通常,在开发 AWS CDK 构造时,组合比继承更受青睐。

NotifyingBucket 构造函数具有典型的构造签名:scopeidprops。最后一个参数 props 是可选的(获取默认值 {}),因为所有 props 都是可选的。(Construct 基类不带 props 参数。) 例如,您可以在应用程序中定义不带 props 的此构造的实例:

TypeScript
new NotifyingBucket(this, 'MyNotifyingBucket');
JavaScript
new NotifyingBucket(this, 'MyNotifyingBucket');
Python
NotifyingBucket(self, "MyNotifyingBucket")
Java
new NotifyingBucket(this, "MyNotifyingBucket");
C#
new NotifyingBucket(this, "MyNotifyingBucket");
Go
NewNotifyingBucket(stack, jsii.String("MyNotifyingBucket"), nil)

或者您可以使用 props(在 Java 中使用附加参数)指定要筛选的路径前缀,例如:

TypeScript
new NotifyingBucket(this, 'MyNotifyingBucket', { prefix: 'images/' });
JavaScript
new NotifyingBucket(this, 'MyNotifyingBucket', { prefix: 'images/' });
Python
NotifyingBucket(self, "MyNotifyingBucket", prefix="images/")
Java
new NotifyingBucket(this, "MyNotifyingBucket", "/images");
C#
new NotifyingBucket(this, "MyNotifyingBucket", new NotifyingBucketProps { Prefix = "/images" });
Go
NewNotifyingBucket(stack, jsii.String("MyNotifyingBucket"), &NotifyingBucketProps{ Prefix: jsii.String("images/"), })

通常,您还需要在构造中公开一些属性或方法。在构造后面隐藏一个话题并不是很有用,因为构造的用户无法订阅它。添加 topic 属性可让使用者访问内部主题,如以下示例所示:

TypeScript
export class NotifyingBucket extends Construct { public readonly topic: sns.Topic; constructor(scope: Construct, id: string, props: NotifyingBucketProps) { super(scope, id); const bucket = new s3.Bucket(this, 'bucket'); this.topic = new sns.Topic(this, 'topic'); bucket.addObjectCreatedNotification(new s3notify.SnsDestination(this.topic), { prefix: props.prefix }); } }
JavaScript
class NotifyingBucket extends Construct { constructor(scope, id, props) { super(scope, id); const bucket = new s3.Bucket(this, 'bucket'); this.topic = new sns.Topic(this, 'topic'); bucket.addObjectCreatedNotification(new s3notify.SnsDestination(this.topic), { prefix: props.prefix }); } } module.exports = { NotifyingBucket };
Python
class NotifyingBucket(Construct): def __init__(self, scope: Construct, id: str, *, prefix=None, **kwargs): super().__init__(scope, id) bucket = s3.Bucket(self, "bucket") self.topic = sns.Topic(self, "topic") bucket.add_object_created_notification(s3notify.SnsDestination(self.topic), s3.NotificationKeyFilter(prefix=prefix))
Java
public class NotifyingBucket extends Construct { public Topic topic = null; public NotifyingBucket(final Construct scope, final String id) { this(scope, id, null, null); } public NotifyingBucket(final Construct scope, final String id, final BucketProps props) { this(scope, id, props, null); } public NotifyingBucket(final Construct scope, final String id, final String prefix) { this(scope, id, null, prefix); } public NotifyingBucket(final Construct scope, final String id, final BucketProps props, final String prefix) { super(scope, id); Bucket bucket = new Bucket(this, "bucket"); topic = new Topic(this, "topic"); if (prefix != null) bucket.addObjectCreatedNotification(new SnsDestination(topic), NotificationKeyFilter.builder().prefix(prefix).build()); } }
C#
public class NotifyingBucket : Construct { public readonly Topic topic; public NotifyingBucket(Construct scope, string id, NotifyingBucketProps props = null) : base(scope, id) { var bucket = new Bucket(this, "bucket"); topic = new Topic(this, "topic"); bucket.AddObjectCreatedNotification(new SnsDestination(topic), new NotificationKeyFilter { Prefix = props?.Prefix }); } }
Go

要在 Go 中实现此目的,我们需要一点额外的操作。原始 NewNotifyingBucket 函数返回了 awss3.Bucket。我们将需要通过创建 NotifyingBucket 构造扩展 Bucket,以包含 topic 成员。然后,函数将返回此类型。

type NotifyingBucket struct { awss3.Bucket topic awssns.Topic } func NewNotifyingBucket(scope constructs.Construct, id *string, props *NotifyingBucketProps) NotifyingBucket { var bucket awss3.Bucket if props == nil { bucket = awss3.NewBucket(scope, jsii.String(*id+"Bucket"), nil) } else { bucket = awss3.NewBucket(scope, jsii.String(*id+"Bucket"), &props.BucketProps) } topic := awssns.NewTopic(scope, jsii.String(*id+"Topic"), nil) if props == nil { bucket.AddObjectCreatedNotification(awss3notifications.NewSnsDestination(topic)) } else { bucket.AddObjectCreatedNotification(awss3notifications.NewSnsDestination(topic), &awss3.NotificationKeyFilter{ Prefix: props.Prefix, }) } var nbucket NotifyingBucket nbucket.Bucket = bucket nbucket.topic = topic return nbucket }

现在,使用者可以订阅该主题,例如:

TypeScript
const queue = new sqs.Queue(this, 'NewImagesQueue'); const images = new NotifyingBucket(this, '/images'); images.topic.addSubscription(new sns_sub.SqsSubscription(queue));
JavaScript
const queue = new sqs.Queue(this, 'NewImagesQueue'); const images = new NotifyingBucket(this, '/images'); images.topic.addSubscription(new sns_sub.SqsSubscription(queue));
Python
queue = sqs.Queue(self, "NewImagesQueue") images = NotifyingBucket(self, prefix="Images") images.topic.add_subscription(sns_sub.SqsSubscription(queue))
Java
NotifyingBucket images = new NotifyingBucket(this, "MyNotifyingBucket", "/images"); images.topic.addSubscription(new SqsSubscription(queue));
C#
var queue = new Queue(this, "NewImagesQueue"); var images = new NotifyingBucket(this, "MyNotifyingBucket", new NotifyingBucketProps { Prefix = "/images" }); images.topic.AddSubscription(new SqsSubscription(queue));
Go
queue := awssqs.NewQueue(stack, jsii.String("NewImagesQueue"), nil) images := NewNotifyingBucket(stack, jsii.String("MyNotifyingBucket"), &NotifyingBucketProps{ Prefix: jsii.String("/images"), }) images.topic.AddSubscription(awssnssubscriptions.NewSqsSubscription(queue, nil))

了解更多

以下视频全面概述了 CDK 构造,并说明了如何在 CDK 应用程序中使用它们。