

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

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

# 識別符和 AWS CDK
<a name="identifiers"></a>

建置 AWS 雲端開發套件 (AWS CDK) 應用程式時，您會使用許多類型的識別符和名稱。若要有效使用 AWS CDK 並避免錯誤，請務必了解識別符的類型。

識別符在建立它們的範圍內必須是唯一的；它們不需要在您的 AWS CDK 應用程式中全域是唯一的。

如果您嘗試在相同範圍內建立具有相同值的識別符， AWS CDK 會擲回例外狀況。

## 建構 IDs
<a name="identifiers-construct-ids"></a>

最常見的識別符 `id`是在執行個體化建構物件時作為第二個引數傳遞的識別符。此識別符與所有識別符一樣，只需要在建立識別符的範圍內是唯一的，這是執行個體化建構物件時的第一個引數。

**注意**  
堆疊`id`的 也是您在 [AWS CDK CLI 參考](cli.md)中用來參考它的識別符。

我們來看一個範例，其中有兩個具有識別符的建構`MyBucket`。第一個定義在具有識別符 的堆疊範圍內`Stack1`。第二個定義在具有識別符 的堆疊範圍內`Stack2`。由於它們是在不同的範圍內定義，這不會造成任何衝突，而且它們可以在相同的應用程式中共存而不會發生問題。

**Example**  

```
import { App, Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';

class MyStack extends Stack {
  constructor(scope: Construct, id: string, props: StackProps = {}) {
    super(scope, id, props);

    new s3.Bucket(this, 'MyBucket');
  }
}

const app = new App();
new MyStack(app, 'Stack1');
new MyStack(app, 'Stack2');
```

```
const { App , Stack } = require('aws-cdk-lib');
const s3 = require('aws-cdk-lib/aws-s3');

class MyStack extends Stack {
  constructor(scope, id, props = {}) {
    super(scope, id, props);

    new s3.Bucket(this, 'MyBucket');
  }
}

const app = new App();
new MyStack(app, 'Stack1');
new MyStack(app, 'Stack2');
```

```
from aws_cdk import App, Construct, Stack, StackProps
from constructs import Construct
from aws_cdk import aws_s3 as s3

class MyStack(Stack):

    def __init__(self, scope: Construct, id: str, **kwargs):

        super().__init__(scope, id, **kwargs)
        s3.Bucket(self, "MyBucket")

app = App()
MyStack(app, 'Stack1')
MyStack(app, 'Stack2')
```

```
// MyStack.java
package com.myorg;

import software.amazon.awscdk.App;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.constructs.Construct;
import software.amazon.awscdk.services.s3.Bucket;

public class MyStack extends Stack {
    public MyStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public MyStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);
        new Bucket(this, "MyBucket");
    }
}

// Main.java
package com.myorg;

import software.amazon.awscdk.App;

public class Main {
    public static void main(String[] args) {
        App app = new App();
        new MyStack(app, "Stack1");
        new MyStack(app, "Stack2");
    }
}
```

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

public class MyStack : Stack
{
    public MyStack(Construct scope, string id, IStackProps props) : base(scope, id, props)
    {
        new Bucket(this, "MyBucket");
    }
}

class Program
{
    static void Main(string[] args)
    {
        var app = new App();
        new MyStack(app, "Stack1");
        new MyStack(app, "Stack2");
    }
}
```

## 路徑
<a name="identifiers-paths"></a>

 AWS CDK 應用程式中的建構會形成以 `App`類別為根的階層。我們將特定建構的 IDs 集合、其父建構、其祖父等稱為建構樹根目錄的*路徑*。

 AWS CDK 通常會將範本中的路徑顯示為字串。來自關卡的 IDs 會以斜線分隔，從根`App`執行個體下的節點開始，通常是堆疊。例如，先前程式碼範例中兩個 Amazon S3 儲存貯體資源的路徑為 `Stack1/MyBucket`和 `Stack2/MyBucket`。

您可以程式設計方式存取任何建構的路徑，如下列範例所示。這會取得 `myConstruct`（或 `my_construct`，因為 Python 開發人員會寫入它） 的路徑。由於 IDs 在建立的範圍內必須是唯一的，因此其路徑在 AWS CDK 應用程式中一律是唯一的。

**Example**  

```
const path: string = myConstruct.node.path;
```

```
const path = myConstruct.node.path;
```

```
path = my_construct.node.path
```

```
String path = myConstruct.getNode().getPath();
```

```
string path = myConstruct.Node.Path;
```

## 唯一 ID
<a name="identifiers-unique-ids"></a>

 AWS CloudFormation 要求範本中的所有邏輯 IDs 都是唯一的。因此， AWS CDK 必須能夠為應用程式中的每個建構產生唯一識別符。資源具有全域唯一的路徑 （從堆疊到特定資源的所有範圍名稱）。因此， AWS CDK 會透過串連路徑的元素並新增 8 位數雜湊來產生必要的唯一識別符。（雜湊是區分不同路徑的必要項目，例如 `A/B/C`和 `A/BC`，這會導致相同的 AWS CloudFormation 識別符。 AWS CloudFormation 識別符是英數字元，不能包含斜線或其他分隔符號字元。) AWS CDK 會將此字串稱為建構的唯一 *ID*。

一般而言，您的 AWS CDK 應用程式應該不需要知道唯一 IDs。不過，您可以透過程式設計方式存取任何建構的唯一 ID，如下列範例所示。

**Example**  

```
const uid: string = Names.uniqueId(myConstruct);
```

```
const uid = Names.uniqueId(myConstruct);
```

```
uid = Names.unique_id(my_construct)
```

```
String uid = Names.uniqueId(myConstruct);
```

```
string uid = Names.Uniqueid(myConstruct);
```

*地址*是另一種唯一識別符，可唯一區分 CDK 資源。衍生自路徑的 SHA-1 雜湊，無法人類讀取。不過，其常數、相對較短的長度 （一律為 42 個十六進位字元），在「傳統」唯一 ID 可能太長的情況下很有用。有些建構可能使用合成 AWS CloudFormation 範本中的地址，而非唯一 ID。同樣地，您的應用程式通常不需要知道其建構結構的地址，但您可以擷取建構結構的地址，如下所示。

**Example**  

```
const addr: string = myConstruct.node.addr;
```

```
const addr = myConstruct.node.addr;
```

```
addr = my_construct.node.addr
```

```
String addr = myConstruct.getNode().getAddr();
```

```
string addr = myConstruct.Node.Addr;
```

## 邏輯 IDs
<a name="identifiers-logical-ids"></a>

當 AWS CDK 將您的應用程式合成到 an AWS CloudFormation 範本時，它會為每個資源產生*邏輯 ID*。 AWS CloudFormation 會使用邏輯 IDs來識別範本中的資源，並在部署之間追蹤這些資源。了解邏輯 IDs 的產生方式，可協助您在重構 CDK 程式碼時避免意外的資源替換。

### 如何產生邏輯 IDs
<a name="identifiers-logical-id-generation"></a>

 AWS CDK 使用下列演算法從建構路徑產生邏輯 IDs：

1. 從建構樹串連路徑元件，不包括堆疊本身。

1. 套用啟發式以提高可讀性 （請參閱[邏輯 ID 路徑元件啟發式](#identifiers-logical-id-heuristics))。

1. 附加完整路徑的 8 個字元雜湊，以確保唯一性。

產生的格式為：

```
<human-readable-portion><8-character-hash>
```

例如，VPC 私有子網路路由表可能會產生邏輯 ID `VPCPrivateSubnet2RouteTable0A19E10E`。

下列規則適用於邏輯 ID 產生：
+ 長度上限為 255 個字元。人類可讀取的部分上限為 240 個字元。
+ 8 個字元雜湊可確保與相同字串`A/BC`串連的 `A/B/C`和 等路徑產生不同的邏輯 IDs。
+ 堆疊 （單一元件路徑） 的直接子項資源直接使用其名稱，無需雜湊，只要名稱為 255 個字元或更少。

### 邏輯 ID 路徑元件啟發式
<a name="identifiers-logical-id-heuristics"></a>

 AWS CDK 會在產生邏輯 IDs 的人類可讀取部分時，將下列啟發式套用至路徑元件。

 `Default` — 已完全移除  
如果路徑元件是 `Default`，CDK 會從人類可讀部分和雜湊輸入中移除它。這表示在新的建構中包裝現有的建構，並命名內部建構`Default`，會產生與原始未包裝建構完全相同的邏輯 ID。這是將一般程式碼安全地重構為更高層級建構的關鍵機制，而不會變更部署的資源身分。

 `Resource` — 僅隱藏在人類可讀取的部分  
如果路徑元件是 `Resource`，CDK 會從人類可讀部分省略它，但仍將其包含在雜湊計算中。L1 (CloudFormation) 建構會使用 `Resource`做為其依據慣例的建構 ID。這可縮短邏輯 IDs而不會失去唯一性。

重複的連續元件 — 已刪除重複項目  
如果上述路徑元件名稱以目前的元件名稱結尾，CDK 會略過目前的元件。這可防止邏輯 IDs 中的備援重複。

### 當您重構時`Default`，使用 保留邏輯 IDs
<a name="identifiers-logical-id-refactoring"></a>

當您將平面堆疊重構為更高層級的建構時，您可以使用 `Default`做為主要資源的建構 ID，以保留其邏輯 ID。這可防止 AWS CloudFormation 在部署期間取代資源。

下列範例顯示具有直接定義之資源的堆疊：

**Example**  

```
export class MyStack extends cdk.Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);
    new s3.Bucket(this, 'DataBucket');
    new lambda.Function(this, 'ProcessFunction', { /* ... */ });
  }
}
```

```
class MyStack extends cdk.Stack {
  constructor(scope, id) {
    super(scope, id);
    new s3.Bucket(this, 'DataBucket');
    new lambda.Function(this, 'ProcessFunction', { /* ... */ });
  }
}
```

```
from aws_cdk import (
    Stack,
    aws_s3 as s3,
    aws_lambda as _lambda,
)
from constructs import Construct

class MyStack(Stack):
    def __init__(self, scope: Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)
        s3.Bucket(self, "DataBucket")
        _lambda.Function(self, "ProcessFunction", # ...
        )
```

```
package com.myorg;

import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.services.s3.Bucket;
import software.amazon.awscdk.services.lambda.Function;

public class MyStack extends Stack {
    public MyStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public MyStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);
        new Bucket(this, "DataBucket");
        Function.Builder.create(this, "ProcessFunction")
            // ...
            .build();
    }
}
```

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

namespace MyApp
{
    public class MyStack : Stack
    {
        public MyStack(Construct scope, string id, StackProps props = null) : base(scope, id, props)
        {
            new Bucket(this, "DataBucket");
            new Function(this, "ProcessFunction", new FunctionProps
            {
                // ...
            });
        }
    }
}
```

```
package main

import (
	"github.com/aws/aws-cdk-go/awscdk/v2"
	"github.com/aws/aws-cdk-go/awscdk/v2/awslambda"
	"github.com/aws/aws-cdk-go/awscdk/v2/awss3"
	"github.com/aws/constructs-go/constructs/v10"
	"github.com/aws/jsii-runtime-go"
)

type MyStackProps struct {
	awscdk.StackProps
}

func NewMyStack(scope constructs.Construct, id string, props *MyStackProps) awscdk.Stack {
	stack := awscdk.NewStack(scope, &id, &props.StackProps)

	awss3.NewBucket(stack, jsii.String("DataBucket"), &awss3.BucketProps{})
	awslambda.NewFunction(stack, jsii.String("ProcessFunction"), &awslambda.FunctionProps{
		// ...
	})

	return stack
}
```

儲存貯體的路徑為 `MyStack/DataBucket/Resource`，會產生 的邏輯 ID`DataBucket<hash>`。

您可以透過命名內部建構 ，將儲存貯體擷取到更高層級的建構中，並保留相同的邏輯 ID`Default`：

**Example**  

```
class DataPipeline extends Construct {
  constructor(scope: Construct, id: string) {
    super(scope, id);
    new s3.Bucket(this, 'Default');  // 'Default' is hidden from logical ID
    new lambda.Function(this, 'ProcessFunction', { /* ... */ });
  }
}

export class MyStack extends cdk.Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);
    new DataPipeline(this, 'DataBucket');
  }
}
```

```
class DataPipeline extends Construct {
  constructor(scope, id) {
    super(scope, id);
    new s3.Bucket(this, 'Default');  // 'Default' is hidden from logical ID
    new lambda.Function(this, 'ProcessFunction', { /* ... */ });
  }
}

class MyStack extends cdk.Stack {
  constructor(scope, id) {
    super(scope, id);
    new DataPipeline(this, 'DataBucket');
  }
}
```

```
from aws_cdk import (
    Stack,
    aws_s3 as s3,
    aws_lambda as _lambda,
)
from constructs import Construct

class DataPipeline(Construct):
    def __init__(self, scope: Construct, id: str) -> None:
        super().__init__(scope, id)
        s3.Bucket(self, "Default")  # 'Default' is hidden from logical ID
        _lambda.Function(self, "ProcessFunction", # ...
        )

class MyStack(Stack):
    def __init__(self, scope: Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)
        DataPipeline(self, "DataBucket")
```

```
package com.myorg;

import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.services.s3.Bucket;
import software.amazon.awscdk.services.lambda.Function;

public class DataPipeline extends Construct {
    public DataPipeline(final Construct scope, final String id) {
        super(scope, id);
        new Bucket(this, "Default");  // 'Default' is hidden from logical ID
        Function.Builder.create(this, "ProcessFunction")
            // ...
            .build();
    }
}

public class MyStack extends Stack {
    public MyStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public MyStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);
        new DataPipeline(this, "DataBucket");
    }
}
```

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

namespace MyApp
{
    public class DataPipeline : Construct
    {
        public DataPipeline(Construct scope, string id) : base(scope, id)
        {
            new Bucket(this, "Default");  // 'Default' is hidden from logical ID
            new Function(this, "ProcessFunction", new FunctionProps
            {
                // ...
            });
        }
    }

    public class MyStack : Stack
    {
        public MyStack(Construct scope, string id, StackProps props = null) : base(scope, id, props)
        {
            new DataPipeline(this, "DataBucket");
        }
    }
}
```

```
package main

import (
	"github.com/aws/aws-cdk-go/awscdk/v2"
	"github.com/aws/aws-cdk-go/awscdk/v2/awslambda"
	"github.com/aws/aws-cdk-go/awscdk/v2/awss3"
	"github.com/aws/constructs-go/constructs/v10"
	"github.com/aws/jsii-runtime-go"
)

type DataPipeline struct {
	constructs.Construct
}

func NewDataPipeline(scope constructs.Construct, id string) constructs.Construct {
	this := constructs.NewConstruct(scope, &id)

	// 'Default' is hidden from logical ID
	awss3.NewBucket(this, jsii.String("Default"), &awss3.BucketProps{})
	awslambda.NewFunction(this, jsii.String("ProcessFunction"), &awslambda.FunctionProps{
		// ...
	})

	return this
}

type MyStackProps struct {
	awscdk.StackProps
}

func NewMyStack(scope constructs.Construct, id string, props *MyStackProps) awscdk.Stack {
	stack := awscdk.NewStack(scope, &id, &props.StackProps)

	NewDataPipeline(stack, "DataBucket")

	return stack
}
```

儲存貯體的路徑現在為 `MyStack/DataBucket/Default/Resource`。由於 從人類可讀取部分和雜湊輸入`Default`中移除 ，因此邏輯 ID 會保持`DataBucket<hash>`與原始相同。

**重要**  
`Default` 每個建構範圍只能有一個 ID 為 的子系。如果您需要相同層級的多個資源，請提供描述 IDs。模式`Default`最適合具有一個主要資源的單一責任建構。

### 限制及考量
<a name="identifiers-logical-id-considerations"></a>

當您使用邏輯 IDs 時，請記住下列事項：
+ 每個建構 ID `Default` 範圍只能指派一個子項。
+ 如果您在部署後變更建構 ID，邏輯 ID 會變更，這會導致 AWS CloudFormation 取代資源。使用 在部署之前`cdk diff`驗證變更。
+ 對於邏輯 IDs 已變更的情況，您可以使用 `cdk refactor`命令將舊邏輯 IDs 映射至新的 ID。如需詳細資訊，請參閱[在重構 CDK 程式碼時保留部署的資源](refactor.md)。
+ 如需有關邏輯 IDs 如何在合成範本中顯示的詳細資訊，請參閱[《 AWS CloudFormation 範本》中的產生邏輯 IDs](configure-synth.md#how-synth-default-logical-ids)。

### 邏輯 ID 穩定性
<a name="identifiers-logical-id-stability"></a>

建立資源之後，請避免變更資源的邏輯 ID。 AWS CloudFormation 會依資源的邏輯 ID 來識別資源。因此，如果您變更資源的邏輯 ID， AWS CloudFormation 會使用新的邏輯 ID 建立新的資源，然後刪除現有的資源。根據資源的類型，這可能會導致服務中斷、資料遺失或兩者。