

這是 AWS CDK v2 開發人員指南。較舊的 CDK v1 已於 2022 年 6 月 1 日進入維護，並於 2023 年 6 月 1 日結束支援。

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 從 AWS 建構程式庫自訂建構
<a name="cfn-layer"></a>

透過 Mixins、Facades、Esc 艙、原始覆寫和自訂資源，從 AWS 建構程式庫自訂建構。

## 使用 Mixins 將功能新增至 L1 建構
<a name="develop-customize-mixins"></a>

混合可讓您將高階功能新增至 L1 建構，而不需要完整的 L2 建構。當 L2 建構模組不適用於服務，或您想要使用 L1 建構模組搭配通常只能透過 L2 建構模組提供的特定功能時，此功能非常有用。

例如，您可以將自動刪除行為新增至 L1 `CfnBucket`，這通常需要 L2 `Bucket` 建構：

**Example**  

```
import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';

const bucket = new s3.CfnBucket(this, 'MyBucket');
bucket.cfnOptions.deletionPolicy = cdk.CfnDeletionPolicy.DELETE;

// Add auto-delete objects behavior using a Mixin
bucket.with(new s3.mixins.BucketAutoDeleteObjects());
```

```
const cdk = require('aws-cdk-lib');
const s3 = require('aws-cdk-lib/aws-s3');

const bucket = new s3.CfnBucket(this, 'MyBucket');
bucket.cfnOptions.deletionPolicy = cdk.CfnDeletionPolicy.DELETE;

// Add auto-delete objects behavior using a Mixin
bucket.with(new s3.mixins.BucketAutoDeleteObjects());
```

```
import aws_cdk as cdk
import aws_cdk.aws_s3 as s3

bucket = s3.CfnBucket(self, "MyBucket")
bucket.cfn_options.deletion_policy = cdk.CfnDeletionPolicy.DELETE

# Add auto-delete objects behavior using a Mixin
bucket.with_(s3.mixins.BucketAutoDeleteObjects())
```

```
import software.amazon.awscdk.*;
import software.amazon.awscdk.services.s3.*;

CfnBucket bucket = new CfnBucket(this, "MyBucket");
bucket.getCfnOptions().setDeletionPolicy(CfnDeletionPolicy.DELETE);

// Add auto-delete objects behavior using a Mixin
bucket.with(new BucketAutoDeleteObjects());
```

```
using Amazon.CDK;
using Amazon.CDK.AWS.S3;

var bucket = new CfnBucket(this, "MyBucket");
bucket.CfnOptions.DeletionPolicy = CfnDeletionPolicy.DELETE;

// Add auto-delete objects behavior using a Mixin
bucket.With(new BucketAutoDeleteObjects());
```

```
bucket := awss3.NewCfnBucket(stack, jsii.String("MyBucket"), nil)
bucket.CfnOptions().SetDeletionPolicy(awscdk.CfnDeletionPolicy_DELETE)

bucket.With(awss3.NewBucketAutoDeleteObjects())
```

每個服務模組的`mixins`命名空間都可以使用混合。您可以將 Mixins 與 [Facades](#develop-customize-facades) 結合，以取得 L1 建構的許可和其他整合。如需 Mixins 的詳細資訊，請參閱 [Mixins](mixins.md)。

## 在 L1 建構模組上使用 Facades 進行整合
<a name="develop-customize-facades"></a>

漸層是資源特定的類別，可為 L1 和 L2 建構提供整合，例如許可、指標和反射。最常見的特徵是授予類別，其提供以意圖為基礎的許可方法。

您可以直接在 L1 建構體上使用 Facades，而無需在 L2 中包裝它們：

**Example**  

```
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as iam from 'aws-cdk-lib/aws-iam';

const bucket = new s3.CfnBucket(this, 'MyBucket');
const role = new iam.Role(this, 'MyRole', {
  assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
});

// Use the Grants Facade directly on the L1 construct
s3.BucketGrants.fromBucket(bucket).read(role);
```

```
const s3 = require('aws-cdk-lib/aws-s3');
const iam = require('aws-cdk-lib/aws-iam');

const bucket = new s3.CfnBucket(this, 'MyBucket');
const role = new iam.Role(this, 'MyRole', {
  assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
});

// Use the Grants Facade directly on the L1 construct
s3.BucketGrants.fromBucket(bucket).read(role);
```

```
import aws_cdk.aws_s3 as s3
import aws_cdk.aws_iam as iam

bucket = s3.CfnBucket(self, "MyBucket")
role = iam.Role(self, "MyRole",
    assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"),
)

# Use the Grants Facade directly on the L1 construct
s3.BucketGrants.from_bucket(bucket).read(role)
```

```
import software.amazon.awscdk.services.s3.*;
import software.amazon.awscdk.services.iam.*;

CfnBucket bucket = new CfnBucket(this, "MyBucket");
Role role = Role.Builder.create(this, "MyRole")
        .assumedBy(new ServicePrincipal("lambda.amazonaws.com"))
        .build();

// Use the Grants Facade directly on the L1 construct
BucketGrants.fromBucket(bucket).read(role);
```

```
using Amazon.CDK.AWS.S3;
using Amazon.CDK.AWS.IAM;

var bucket = new CfnBucket(this, "MyBucket");
var role = new Role(this, "MyRole", new RoleProps
{
    AssumedBy = new ServicePrincipal("lambda.amazonaws.com")
});

// Use the Grants Facade directly on the L1 construct
BucketGrants.FromBucket(bucket).Read(role);
```

```
bucket := awss3.NewCfnBucket(stack, jsii.String("MyBucket"), nil)
role := awsiam.NewRole(stack, jsii.String("MyRole"), &awsiam.RoleProps{
    AssumedBy: awsiam.NewServicePrincipal(jsii.String("lambda.amazonaws.com"), nil),
})

awss3.BucketGrants_FromBucket(bucket).Read(role, nil)
```

如需淡化的詳細資訊，請參閱[淡化](facades.md)。

當 Mixins 和 Facades 不涵蓋您的使用案例時，您可以使用逃生艙和原始覆寫來自訂較低層級的建構。

## 使用逃生艙
<a name="develop-customize-escape"></a>

 AWS 建構程式庫提供不同抽象層級的[建構](constructs.md)。

在最高層級，您的 AWS CDK 應用程式及其中的堆疊本身就是整個雲端基礎設施的抽象概念，或是其中的大量區塊。它們可以進行參數化，以將它們部署在不同的環境或滿足不同的需求。

抽象是設計和實作雲端應用程式的強大工具。 AWS CDK 不僅為您提供了使用其抽象概念建置的強大功能，還可以建立新的抽象概念。使用現有的開放原始碼 L2 和 L3 建構做為指引，您可以建置自己的 L2 和 L3 建構，以反映組織的最佳實務和意見。

沒有任何抽象是完美的，即使是好的抽象也無法涵蓋每個可能的使用案例。在開發期間，您可能會找到幾乎符合您需求的建構，需要小型或大型自訂。

因此， AWS CDK 提供*分離*建構模型的方法。這包括移至較低層級的抽象或完全移至不同的模型。逃生艙可讓您*逃生* AWS CDK 範例，並以符合您需求的方式進行自訂。然後，您可以將變更包裝在新的建構中，以抽象化基礎複雜性，並為其他開發人員提供乾淨的 API。

以下是您可以使用逃生艙的情況範例：
+  AWS 服務功能可透過 AWS CloudFormation 使用，但沒有 L2 建構。
+  AWS 服務功能可透過 AWS CloudFormation 使用，而且該服務有 L2 建構，但這些結構尚未公開該功能。由於 L2 建構由 CDK 團隊策劃，因此可能無法立即用於新功能。
+ 此功能尚未透過 AWS CloudFormation 提供。

  若要判斷某個功能是否可透過 AWS CloudFormation 使用，請參閱[AWS 資源和屬性類型參考](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html)。

### 開發 L1 建構的逃生艙
<a name="develop-customize-escape-l1"></a>

如果 L2 建構模組不適用於服務，您可以使用自動產生的 L1 建構模組。這些資源可以透過名稱識別，以 開頭`Cfn`，例如 `CfnBucket`或 `CfnRole`。您可以像使用 equivalent AWS CloudFormation 資源一樣執行個體化它們。

例如，若要在啟用分析的情況下執行個體化低階 Amazon S3 儲存貯體 L1，您可以撰寫如下所示的內容。

**Example**  

```
new s3.CfnBucket(this, 'amzn-s3-demo-bucket', {
  analyticsConfigurations: [
    {
      id: 'Config',
      // ...
    }
  ]
});
```

```
new s3.CfnBucket(this, 'amzn-s3-demo-bucket', {
  analyticsConfigurations: [
    {
      id: 'Config'
      // ...
    }
  ]
});
```

```
s3.CfnBucket(self, "amzn-s3-demo-bucket",
    analytics_configurations: [
        dict(id="Config",
             # ...
             )
    ]
)
```

```
CfnBucket.Builder.create(this, "amzn-s3-demo-bucket")
    .analyticsConfigurations(Arrays.asList(java.util.Map.of(    // Java 9 or later
        "id", "Config", // ...
    ))).build();
```

```
new CfnBucket(this, 'amzn-s3-demo-bucket', new CfnBucketProps {
    AnalyticsConfigurations = new Dictionary<string, string>
    {
        ["id"] = "Config",
        // ...
    }
});
```

在極少數情況下，您可能想要定義沒有對應`CfnXxx`類別的資源。這可能是尚未在 AWS CloudFormation 資源規格中發佈的新資源類型。在這種情況下，您可以`cdk.CfnResource`直接執行個體化 ，並指定資源類型和屬性。如以下範例所示。

**Example**  

```
new cdk.CfnResource(this, 'amzn-s3-demo-bucket', {
  type: 'AWS::S3::Bucket',
  properties: {
    // Note the PascalCase here! These are CloudFormation identifiers.
    AnalyticsConfigurations: [
      {
        Id: 'Config',
        // ...
      }
    ]
  }
});
```

```
new cdk.CfnResource(this, 'amzn-s3-demo-bucket', {
  type: 'AWS::S3::Bucket',
  properties: {
    // Note the PascalCase here! These are CloudFormation identifiers.
    AnalyticsConfigurations: [
      {
        Id: 'Config'
        // ...
      }
    ]
  }
});
```

```
cdk.CfnResource(self, 'amzn-s3-demo-bucket',
  type="AWS::S3::Bucket",
  properties=dict(
    # Note the PascalCase here! These are CloudFormation identifiers.
    "AnalyticsConfigurations": [
      {
        "Id": "Config",
        # ...
      }
    ]
  )
)
```

```
CfnResource.Builder.create(this, "amzn-s3-demo-bucket")
        .type("AWS::S3::Bucket")
        .properties(java.util.Map.of(    // Map.of requires Java 9 or later
            // Note the PascalCase here! These are CloudFormation identifiers
            "AnalyticsConfigurations", Arrays.asList(
                    java.util.Map.of("Id", "Config", // ...
                    ))))
        .build();
```

```
new CfnResource(this, "amzn-s3-demo-bucket", new CfnResourceProps
{
    Type = "AWS::S3::Bucket",
    Properties = new Dictionary<string, object>
    {   // Note the PascalCase here! These are CloudFormation identifiers
        ["AnalyticsConfigurations"] = new Dictionary<string, string>[]
        {
            new Dictionary<string, string> {
                ["Id"] = "Config"
            }
        }
    }
});
```

### 開發 L2 建構的逃生艙
<a name="develop-customize-escape-l2"></a>

如果 L2 建構模組缺少功能，或者您嘗試解決問題，您可以修改L12 建構模組封裝的 L2 建構模組。

所有 L2 建構包含其中對應的 L1 建構。例如，高階`Bucket`建構模組會包裝低階`CfnBucket`建構模組。由於 直接`CfnBucket`對應至 AWS CloudFormation 資源，因此會公開透過 AWS CloudFormation 提供的所有功能。

存取 L1 建構的基本方法是使用 `construct.node.defaultChild`(Python：`default_child`)，將其轉換為正確的類型 （如有必要），並修改其屬性。同樣地，讓我們以 為例`Bucket`。

**Example**  

```
// Get the CloudFormation resource
const cfnBucket = bucket.node.defaultChild as s3.CfnBucket;

// Change its properties
cfnBucket.analyticsConfiguration = [
  {
    id: 'Config',
    // ...
  }
];
```

```
// Get the CloudFormation resource
const cfnBucket = bucket.node.defaultChild;

// Change its properties
cfnBucket.analyticsConfiguration = [
  {
    id: 'Config'
    // ...
  }
];
```

```
# Get the CloudFormation resource
cfn_bucket = bucket.node.default_child

# Change its properties
cfn_bucket.analytics_configuration = [
    {
        "id": "Config",
        # ...
    }
]
```

```
// Get the CloudFormation resource
CfnBucket cfnBucket = (CfnBucket)bucket.getNode().getDefaultChild();

cfnBucket.setAnalyticsConfigurations(
        Arrays.asList(java.util.Map.of(    // Java 9 or later
            "Id", "Config", // ...
        ));
)
```

```
// Get the CloudFormation resource
var cfnBucket = (CfnBucket)bucket.Node.DefaultChild;

cfnBucket.AnalyticsConfigurations = new List<object> {
    new Dictionary<string, string>
    {
        ["Id"] = "Config",
        // ...
    }
};
```

您也可以使用此物件來變更 AWS CloudFormation 選項，例如 `Metadata`和 `UpdatePolicy`。

**Example**  

```
cfnBucket.cfnOptions.metadata = {
  MetadataKey: 'MetadataValue'
};
```

```
cfnBucket.cfnOptions.metadata = {
  MetadataKey: 'MetadataValue'
};
```

```
cfn_bucket.cfn_options.metadata = {
    "MetadataKey": "MetadataValue"
}
```

```
cfnBucket.getCfnOptions().setMetadata(java.util.Map.of(    // Java 9+
    "MetadataKey", "Metadatavalue"));
```

```
cfnBucket.CfnOptions.Metadata = new Dictionary<string, object>
{
    ["MetadataKey"] = "Metadatavalue"
};
```

## 使用取消逸出艙門
<a name="develop-customize-unescape"></a>

 AWS CDK 也提供*提升*抽象層級的功能，我們可能會將其稱為「取消逸出」艙。如果您有 L1 建構，例如 `CfnBucket`，您可以建立新的 L2 建構 (`Bucket`在此案例中為 ) 來包裝 L1 建構。

這在您建立 L1 資源時很方便，但想要將其與需要 L2 資源的建構搭配使用。

**提示**  
如果您只需要 L1 建構上的許可或其他整合，則不需要將其包裝在 L2 中。請改為在 L1 上直接使用像 Grants 類別的 [Facades](facades.md)，例如 `BucketGrants.fromBucket(cfnBucket).read(role)`。

您可以在名為 `.fromCfnXxxxx()`的 L2 類別上使用靜態方法來移至較高的抽象層級，例如，`Bucket.fromCfnBucket()`Amazon S3 儲存貯體。L1 資源是唯一的參數。

**Example**  

```
b1 = new s3.CfnBucket(this, "buck09", { ... });
b2 = s3.Bucket.fromCfnBucket(b1);
```

```
b1 = new s3.CfnBucket(this, "buck09", { ...} );
b2 = s3.Bucket.fromCfnBucket(b1);
```

```
b1 = s3.CfnBucket(self, "buck09", ...)
 b2 = s3.from_cfn_bucket(b1)
```

```
CfnBucket b1 = CfnBucket.Builder.create(this, "buck09")
								// ....
		                        .build();
IBucket b2 = Bucket.fromCfnBucket(b1);
```

```
var b1 = new CfnBucket(this, "buck09", new CfnBucketProps { ... });
var v2 = Bucket.FromCfnBucket(b1);
```

從 L1 建構模組建立的 L2 建構模組是參考 L1 資源的代理物件，類似於從資源名稱、ARNs或查詢建立的物件。這些建構的修改不會影響最終合成 AWS CloudFormation 範本 （不過，由於您有 L1 資源，您可以改為修改該範本）。如需代理物件的詳細資訊，請參閱[參考 AWS 帳戶中的資源](resources.md#resources-external)。

為了避免混淆，請勿建立多個參考相同 L2 建構的 L12 建構。例如，如果您`Bucket`使用[上一節](#develop-customize-escape-l2)中的 技術`CfnBucket`從 擷取 ，則不應`Bucket.fromCfnBucket()`使用該 呼叫 來建立第二個`Bucket`執行個體`CfnBucket`。它實際上如您預期般運作 （只會` AWS::S3::Bucket`合成一個），但讓您的程式碼更難以維護。

## 使用原始覆寫
<a name="develop-customize-override"></a>

如果 L1 建構中缺少屬性，您可以使用原始覆寫略過所有輸入。這也可讓您刪除合成屬性。

使用其中一種`addOverride`方法 (Python：`add_override`) 方法，如下列範例所示。

**Example**  

```
// Get the CloudFormation resource
const cfnBucket = bucket.node.defaultChild as s3.CfnBucket;

// Use dot notation to address inside the resource template fragment
cfnBucket.addOverride('Properties.VersioningConfiguration.Status', 'NewStatus');
cfnBucket.addDeletionOverride('Properties.VersioningConfiguration.Status');

// use index (0 here) to address an element of a list
cfnBucket.addOverride('Properties.Tags.0.Value', 'NewValue');
cfnBucket.addDeletionOverride('Properties.Tags.0');

// addPropertyOverride is a convenience function for paths starting with "Properties."
cfnBucket.addPropertyOverride('VersioningConfiguration.Status', 'NewStatus');
cfnBucket.addPropertyDeletionOverride('VersioningConfiguration.Status');
cfnBucket.addPropertyOverride('Tags.0.Value', 'NewValue');
cfnBucket.addPropertyDeletionOverride('Tags.0');
```

```
// Get the CloudFormation resource
const cfnBucket = bucket.node.defaultChild ;

// Use dot notation to address inside the resource template fragment
cfnBucket.addOverride('Properties.VersioningConfiguration.Status', 'NewStatus');
cfnBucket.addDeletionOverride('Properties.VersioningConfiguration.Status');

// use index (0 here) to address an element of a list
cfnBucket.addOverride('Properties.Tags.0.Value', 'NewValue');
cfnBucket.addDeletionOverride('Properties.Tags.0');

// addPropertyOverride is a convenience function for paths starting with "Properties."
cfnBucket.addPropertyOverride('VersioningConfiguration.Status', 'NewStatus');
cfnBucket.addPropertyDeletionOverride('VersioningConfiguration.Status');
cfnBucket.addPropertyOverride('Tags.0.Value', 'NewValue');
cfnBucket.addPropertyDeletionOverride('Tags.0');
```

```
# Get the CloudFormation resource
cfn_bucket = bucket.node.default_child

# Use dot notation to address inside the resource template fragment
cfn_bucket.add_override("Properties.VersioningConfiguration.Status", "NewStatus")
cfn_bucket.add_deletion_override("Properties.VersioningConfiguration.Status")

# use index (0 here) to address an element of a list
cfn_bucket.add_override("Properties.Tags.0.Value", "NewValue")
cfn_bucket.add_deletion_override("Properties.Tags.0")

# addPropertyOverride is a convenience function for paths starting with "Properties."
cfn_bucket.add_property_override("VersioningConfiguration.Status", "NewStatus")
cfn_bucket.add_property_deletion_override("VersioningConfiguration.Status")
cfn_bucket.add_property_override("Tags.0.Value", "NewValue")
cfn_bucket.add_property_deletion_override("Tags.0")
```

```
// Get the CloudFormation resource
CfnBucket cfnBucket = (CfnBucket)bucket.getNode().getDefaultChild();

// Use dot notation to address inside the resource template fragment
cfnBucket.addOverride("Properties.VersioningConfiguration.Status", "NewStatus");
cfnBucket.addDeletionOverride("Properties.VersioningConfiguration.Status");

// use index (0 here) to address an element of a list
cfnBucket.addOverride("Properties.Tags.0.Value", "NewValue");
cfnBucket.addDeletionOverride("Properties.Tags.0");

// addPropertyOverride is a convenience function for paths starting with "Properties."
cfnBucket.addPropertyOverride("VersioningConfiguration.Status", "NewStatus");
cfnBucket.addPropertyDeletionOverride("VersioningConfiguration.Status");
cfnBucket.addPropertyOverride("Tags.0.Value", "NewValue");
cfnBucket.addPropertyDeletionOverride("Tags.0");
```

```
// Get the CloudFormation resource
var cfnBucket = (CfnBucket)bucket.node.defaultChild;

// Use dot notation to address inside the resource template fragment
cfnBucket.AddOverride("Properties.VersioningConfiguration.Status", "NewStatus");
cfnBucket.AddDeletionOverride("Properties.VersioningConfiguration.Status");

// use index (0 here) to address an element of a list
cfnBucket.AddOverride("Properties.Tags.0.Value", "NewValue");
cfnBucket.AddDeletionOverride("Properties.Tags.0");

// addPropertyOverride is a convenience function for paths starting with "Properties."
cfnBucket.AddPropertyOverride("VersioningConfiguration.Status", "NewStatus");
cfnBucket.AddPropertyDeletionOverride("VersioningConfiguration.Status");
cfnBucket.AddPropertyOverride("Tags.0.Value", "NewValue");
cfnBucket.AddPropertyDeletionOverride("Tags.0");
```

## 使用自訂資源
<a name="develop-customize-custom"></a>

如果此功能無法透過 AWS CloudFormation 使用，但只能透過直接 API 呼叫使用，您必須撰寫 an AWS CloudFormation 自訂資源，才能進行您需要的 API 呼叫。您可以使用 AWS CDK 撰寫自訂資源，並將其包裝成一般建構界面。從建構的消費者的角度來看，體驗會感覺原生。

建置自訂資源涉及撰寫 Lambda 函數，以回應資源的 `CREATE`、 `UPDATE`和`DELETE`生命週期事件。如果您的自訂資源只需要進行單一 API 呼叫，請考慮使用 [AwsCustomResource](https://github.com/awslabs/aws-cdk/tree/master/packages/%40aws-cdk/custom-resources)。這可讓您在 an AWS CloudFormation 部署期間執行任意 SDK 呼叫。否則，您應該撰寫自己的 Lambda 函數來執行您需要完成的工作。

主旨太廣泛，無法完全涵蓋此處，但以下連結應該會讓您開始使用：
+  [自訂資源](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html) 
+  [自訂資源範例](https://github.com/aws-samples/aws-cdk-examples/tree/master/typescript/custom-resource/) 
+ 如需更完整的範例，請參閱 CDK 標準程式庫中的 [DnsValidatedCertificate](https://github.com/awslabs/aws-cdk/blob/master/packages/@aws-cdk/aws-certificatemanager/lib/dns-validated-certificate.ts) 類別。這會實作為自訂資源。