

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

# 使用 Java 建置 Lambda 函數
<a name="lambda-java"></a>

您可以在 AWS Lambda中執行 Java 程式碼。Lambda 提供用於執行程式碼來處理事件的 Java [執行期](lambda-runtimes.md)。您的程式碼會在 Amazon Linux 環境中執行，其中包含您管理之 AWS Identity and Access Management (IAM) 角色的 AWS 登入資料。

Lambda 支援以下 Java 執行期。<a name="java-runtimes"></a>


| Name | 識別符 | 作業系統 | 取代日期 | 封鎖函數建立 | 封鎖函數更新 | 
| --- | --- | --- | --- | --- | --- | 
|  Java 25  |  `java25`  |  Amazon Linux 2023  |   2029 年 6 月 30 日   |   2029 年 7 月 31 日   |   2029 年 8 月 31 日   | 
|  Java 21  |  `java21`  |  Amazon Linux 2023  |   2029 年 6 月 30 日   |   2029 年 7 月 31 日   |   2029 年 8 月 31 日   | 
|  Java 17  |  `java17`  |  Amazon Linux 2  |   2027 年 6 月 30 日   |   2027 年 7 月 31 日   |   2027 年 8 月 31 日   | 
|  Java 11  |  `java11`  |  Amazon Linux 2  |   2027 年 6 月 30 日   |   2027 年 7 月 31 日   |   2027 年 8 月 31 日   | 
|  Java 8  |  `java8.al2`  |  Amazon Linux 2  |   2027 年 6 月 30 日   |   2027 年 7 月 31 日   |   2027 年 8 月 31 日   | 

AWS 為 Java 函數提供下列程式庫。這些程式庫可透過 [Maven Central Repository](https://search.maven.org/search?q=g:com.amazonaws) 取得。
+ [com.amazonaws:aws-lambda-java-core](https://github.com/aws/aws-lambda-java-libs/tree/master/aws-lambda-java-core) (必要) - 定義處理常式方法介面，以及執行期傳遞給處理常式的內容物件。如果您定義自己的輸入類型，這是您需要的唯一程式庫。
+ [com.amazonaws:aws-lambda-java-events](https://github.com/aws/aws-lambda-java-libs/tree/master/aws-lambda-java-events) - 來自調用 Lambda 函數的服務的輸入事件類型。
+ [com.amazonaws:aws-lambda-java-log4j2](https://github.com/aws/aws-lambda-java-libs/tree/master/aws-lambda-java-log4j2) - 一個 Apache Log4j 2 的附加程式庫，您可以使用它將當前調用的請求 ID 新增至[函數日誌](java-logging.md)。
+ [AWS 適用於 Java 的 SDK 2.0](https://github.com/aws/aws-sdk-java-v2) – 適用於 Java 程式設計語言的官方 AWS SDK。

請將這些程式庫新增至建置定義中，如下所示：

------
#### [ Gradle ]

```
dependencies {
    implementation 'com.amazonaws:aws-lambda-java-core:1.2.2'
    implementation 'com.amazonaws:aws-lambda-java-events:3.11.1'
    runtimeOnly 'com.amazonaws:aws-lambda-java-log4j2:1.5.1'
}
```

------
#### [ Maven ]

```
  <dependencies>
    <dependency>
      <groupId>com.amazonaws</groupId>
      <artifactId>aws-lambda-java-core</artifactId>
      <version>1.2.2</version>
    </dependency>
    <dependency>
      <groupId>com.amazonaws</groupId>
      <artifactId>aws-lambda-java-events</artifactId>
      <version>3.11.1</version>
    </dependency>
    <dependency>
      <groupId>com.amazonaws</groupId>
      <artifactId>aws-lambda-java-log4j2</artifactId>
      <version>1.5.1</version>
    </dependency>
  </dependencies>
```

------

**重要**  
請勿使用 JDK API 的私有元件，如私有欄位、方法或類別。非公有 API 元件可能在任何更新中發生變更或被移除，導致您的應用程式中斷。

**若要建立 Lambda 函數**

1. 開啟 [Lambda 主控台](https://console.aws.amazon.com/lambda)。

1. 選擇**建立函數**。

1. 進行下列設定：
   + **函數名稱**：輸入函數名稱。
   + **執行時間**：選擇 **Java 25**。

1. 選擇**建立函數**。

主控台將建立一個 Lambda 函數，它具有名為 `Hello` 的處理常式類別。由於 Java 是一種編譯語言，因此您無法在 Lambda 主控台中檢視或編輯原始碼，但可以修改其組態，加以調用，並設定觸發條件。

**注意**  
若要開始在您的本機環境中開發應用程式，請部署本指南 GitHub 儲存庫中可用的其中一個[範例應用程式](java-samples.md)。

`Hello` 類別有一個名為 `handleRequest` 的函式，其接受事件物件與內容物件。這就是在調用函數時，Lambda 呼叫的[處理常式函數](java-handler.md)。Java 函數執行期會從 Lambda 取得調用事件並其傳遞至處理常式。在函式組態中，處理常式值為 `example.Hello::handleRequest`。

若要更新函數的程式碼，您可建立部署套件，這是包含函數程式碼的 ZIP 封存檔。隨著函式開發的進展，您需要將函式程式碼存放於原始碼控制系統、加入程式庫並進行自動化部署。首先，透過命令列[建立部署套件](java-package.md)並更新您的程式碼。

除了傳遞調用事件外，函式執行期還會傳遞內容物件至處理常式。[內容物件](java-context.md)包含了有關調用、函式以及執行環境的額外資訊。更多詳細資訊將另由環境變數提供。

Lambda 函數隨附有 CloudWatch Logs 記錄群組。函數執行期會將每次調用的詳細資訊傳送至 CloudWatch Logs。它在調用期間會轉送[您的函數輸出的任何記錄](java-logging.md)。如果您的函數傳回錯誤，Lambda 會對該錯誤進行格式化之後傳回給調用端。

**Topics**
+ [在 Java 中定義 Lambda 函數處理常式](java-handler.md)
+ [使用 .zip 或 JAR 封存檔部署 Java Lambda 函數](java-package.md)
+ [使用容器映像部署 Java Lambda 函數](java-image.md)
+ [使用 Java Lambda 函數的層](java-layers.md)
+ [自訂 Lambda Java 函數的序列化](java-custom-serialization.md)
+ [自訂 Lambda 函數的 Java 執行時期啟動行為](java-customization.md)
+ [使用 Lambda 內容物件擷取 Java 函數資訊](java-context.md)
+ [記錄和監控 Java Lambda 函數](java-logging.md)
+ [在 中檢測 Java 程式碼 AWS Lambda](java-tracing.md)
+ [的 Java 範例應用程式 AWS Lambda](java-samples.md)

# 在 Java 中定義 Lambda 函數處理常式
<a name="java-handler"></a>

Lambda 函數*處理常式*是您的函數程式碼中處理事件的方法。當有人呼叫您的函數時，Lambda 會執行處理常式方法。函數會執行，直到處理常式傳回回應、結束或逾時為止。

本頁介紹了如何在 Java 中使用 Lambda 函式處理常式，包括專案設定選項、命名慣例及最佳實務。本頁還提供了一個 Java Lambda 函式範例，該函式會取得訂單的相關資訊、產生文字檔案收據，並將該檔案放入 Amazon Simple Storage Service (Amazon S3) 儲存貯體。如需編寫函數後如何部署函數的詳細資訊，請參閱[使用 .zip 或 JAR 封存檔部署 Java Lambda 函數](java-package.md)或[使用容器映像部署 Java Lambda 函數](java-image.md)。

**Topics**
+ [設定 Java 處理常式專案](#java-handler-setup)
+ [Java Lambda 函式程式碼範例](#java-example-code)
+ [Java 處理常式的有效類別定義](#java-handler-signatures)
+ [處理常式命名慣例](#java-example-naming)
+ [定義和存取輸入事件物件](#java-handler-input)
+ [存取和使用 Lambda 內容物件](#java-example-context)
+ [在處理常式中使用適用於 Java v2 的 AWS SDK](#java-example-sdk-usage)
+ [存取環境變數](#java-example-envvars)
+ [使用全域狀態](#java-handler-state)
+ [Java Lambda 函數的程式碼最佳實務](#java-best-practices)

## 設定 Java 處理常式專案
<a name="java-handler-setup"></a>

使用 Java 開發 Lambda 函式時，流程涉及編寫程式碼、編譯程式碼，以及將編譯後的成品部署至 Lambda。可以透過各種方式初始化 Java Lambda 專案。例如，您可以使用下列工具：[適用於 Lambda 函式的 Maven Archetype](https://github.com/aws/aws-sdk-java-v2/tree/master/archetypes/archetype-lambda)、AWS SAM CLI 的[ sam init 命令](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-init.html)，甚或在偏好的 IDE (例如 IntelliJ IDEA 或 Visual Studio Code) 中建立標準 Java 專案設定。或者，您可以手動建立所需的檔案結構。

一個典型的 Java Lambda 函式專案遵循以下一般結構：

```
/project-root
    └ src
        └ main
            └ java
                └ example
                    └ OrderHandler.java (contains main handler)
                    └ <other_supporting_classes>
     └ build.gradle OR pom.xml
```

可以使用 Maven 或 Gradle 建置專案並管理相依項。

函式的主要處理常式邏輯位於 `src/main/java/example` 目錄下的 Java 檔案中。在此頁面上的範例中，我們將該檔案命名為 `OrderHandler.java`。除了該檔案外，您亦可視需要納入其他 Java 類別。將函式部署至 Lambda 時，請務必指定包含 Lambda 在調用期間應調用的主要處理常式方法的 Java 類別。

## Java Lambda 函式程式碼範例
<a name="java-example-code"></a>

以下 Java 21 Lambda 函式程式碼範例會取得訂單的相關資訊、產生文字檔案收據，並將該檔案放入 Amazon S3 儲存貯體。

**Example `OrderHandler.java` Lambda 函數**  

```
package example;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.model.S3Exception;

import java.nio.charset.StandardCharsets;

/**
 * Lambda handler for processing orders and storing receipts in S3.
 */
public class OrderHandler implements RequestHandler<OrderHandler.Order, String> {

    private static final S3Client S3_CLIENT = S3Client.builder().build();

    /**
     * Record to model the input event.
     */
    public record Order(String orderId, double amount, String item) {}

    @Override
    public String handleRequest(Order event, Context context) {
        try {
            // Access environment variables
            String bucketName = System.getenv("RECEIPT_BUCKET");
            if (bucketName == null || bucketName.isEmpty()) {
                throw new IllegalArgumentException("RECEIPT_BUCKET environment variable is not set");
            }

            // Create the receipt content and key destination
            String receiptContent = String.format("OrderID: %s\nAmount: $%.2f\nItem: %s",
                    event.orderId(), event.amount(), event.item());
            String key = "receipts/" + event.orderId() + ".txt";

            // Upload the receipt to S3
            uploadReceiptToS3(bucketName, key, receiptContent);

            context.getLogger().log("Successfully processed order " + event.orderId() +
                    " and stored receipt in S3 bucket " + bucketName);
            return "Success";

        } catch (Exception e) {
            context.getLogger().log("Failed to process order: " + e.getMessage());
            throw new RuntimeException(e);
        }
    }

    private void uploadReceiptToS3(String bucketName, String key, String receiptContent) {
        try {
            PutObjectRequest putObjectRequest = PutObjectRequest.builder()
                    .bucket(bucketName)
                    .key(key)
                    .build();

            // Convert the receipt content to bytes and upload to S3
            S3_CLIENT.putObject(putObjectRequest, RequestBody.fromBytes(receiptContent.getBytes(StandardCharsets.UTF_8)));
        } catch (S3Exception e) {
            throw new RuntimeException("Failed to upload receipt to S3: " + e.awsErrorDetails().errorMessage(), e);
        }
    }
}
```

此 `OrderHandler.java` 檔案包含以下程式碼區段：
+ `package example`：在 Java 中，此套件名稱可自訂，但必須與專案的目錄結構相符。本處採用 `package example`，原因在於目錄結構為 `src/main/java/example`。
+ `import` 陳述式：用於匯入 Lambda 函式所需的 Java 類別。
+ `public class OrderHandler ...`：此程式碼會定義您的 Java 類別，且必須為[有效的類別定義](#java-handler-signatures)。
+ `private static final S3Client S3_CLIENT ...`：此程式碼在類別的所有方法外部初始化 S3 用戶端。這會使 Lambda 在[初始化階段](lambda-runtime-environment.md#runtimes-lifecycle-ib)執行此程式碼。
+ `public record Order ...`：在此自訂 Java [記錄](https://openjdk.org/jeps/395)中定義預期輸入事件的結構。
+ `public String handleRequest(Order event, Context context)`：這是**主要處理常式方法**，其中包含應用程式的主要邏輯。
+ `private void uploadReceiptToS3(...) {}`：這是主要 `handleRequest` 處理常式方法所參考的協助程式方法。

### build.gradle 與 pom.xml 檔案範例
<a name="java-gradle-maven-example"></a>

此函式附帶下列 `build.gradle` 或 `pom.xml` 檔案。

------
#### [ build.gradle ]

```
plugins {
    id 'java'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'com.amazonaws:aws-lambda-java-core:1.2.3'
    implementation 'software.amazon.awssdk:s3:2.28.29'
    implementation 'org.slf4j:slf4j-nop:2.0.16'
}

task buildZip(type: Zip) {
    from compileJava
    from processResources
    into('lib') {
        from configurations.runtimeClasspath
    }
}

java {
    sourceCompatibility = JavaVersion.VERSION_21
    targetCompatibility = JavaVersion.VERSION_21
}

build.dependsOn buildZip
```

------
#### [ pom.xml ]

```
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>example-java</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>example-java-function</name>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-lambda-java-core</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>s3</artifactId>
            <version>2.28.29</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-nop</artifactId>
            <version>2.0.16</version>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.5.2</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.4.1</version>
                <configuration>
                    <createDependencyReducedPom>false</createDependencyReducedPom>
                    <filters>
                        <filter>
                            <artifact>*:*</artifact>
                            <excludes>
                                <exclude>META-INF/*</exclude>
                                <exclude>META-INF/versions/**</exclude>
                            </excludes>
                        </filter>
                    </filters>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.13.0</version>
                <configuration>
                    <release>21</release>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
```

------

若要讓此函式正常運作，其[執行角色](lambda-intro-execution-role.md)必須允許 `s3:PutObject` 動作。此外，請確保定義 `RECEIPT_BUCKET` 環境變數。成功調用後，Amazon S3 儲存貯體應包含收據檔案。

**注意**  
此函式可能需要額外的組態設定，才能順利執行而不發生逾時。建議設定 256 MB 記憶體以及 10 秒逾時。首次調用可能因[冷啟動](lambda-runtime-environment.md#cold-start-latency)而耗費更長時間。後續調用因執行環境可重複使用，執行速度會大幅提升。

## Java 處理常式的有效類別定義
<a name="java-handler-signatures"></a>

為了定義類別，[aws-lambda-java-core](https://github.com/aws/aws-lambda-java-libs/tree/master/aws-lambda-java-core) 程式庫定義了處理常式方法的兩個介面。透過使用這些預設介面，可簡化處理常式的設定流程，並在編譯階段驗證方法簽章。
+ [ com.amazonaws.services.lambda.runtime.RequestHandler](https://github.com/aws/aws-lambda-java-libs/blob/master/aws-lambda-java-core/src/main/java/com/amazonaws/services/lambda/runtime/RequestHandler.java)
+ [ com.amazonaws.services.lambda.runtime.RequestStreamHandler](https://github.com/aws/aws-lambda-java-libs/blob/master/aws-lambda-java-core/src/main/java/com/amazonaws/services/lambda/runtime/RequestStreamHandler.java)

`RequestHandler` 介面是一個一般類型，它有兩個參數：輸入類型和輸出類型。兩種類型都必須是物件。在此範例中，`OrderHandler` 類別會實作 `RequestHandler<OrderHandler.Order, String>`。輸入類型是我們在類別中定義的 `Order` 記錄，輸出類型是 `String`。

```
public class OrderHandler implements RequestHandler<OrderHandler.Order, String> {
    ...
}
```

當您使用此介面時，Java 執行時期會將事件反序列化為具有輸入類型的物件，並將輸出序列化為文字。當內建序列化與您的輸入和輸出類型一同作業時，請使用此介面。

若要使用自訂序列化，您可以實作 `RequestStreamHandler` 介面。透過此介面，Lambda 會將處理常式傳遞給一個輸入串流和輸出串流。處理常式會從輸入串流讀取位元組，寫入到輸出串流，並傳回 void 值。如需使用 Java 21 執行時期的實作範例，請參閱 [ HandlerStream.java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-basic/src/main/java/example/HandlerStream.java)。

若您的 Java 函式僅使用基本類型與泛型類型 (即 `String`、`Integer`、`List` 或 `Map`)，則無需實作介面。例如，若函式接收一個 `Map<String, String>` 輸入並傳回 `String`，則類別定義和處理常式簽章可能如下所示：

```
public class ExampleHandler {
    public String handleRequest(Map<String, String> input, Context context) {
        ...
    }
}
```

此外，如果未實作介面，則[內容](java-context.md)物件是選用項目。例如，類別定義和處理常式簽章可能如下所示：

```
public class NoContextHandler {
   public String handleRequest(Map<String, String> input) {
        ...
   }
}
```

## 處理常式命名慣例
<a name="java-example-naming"></a>

對於 Java 中的 Lambda 函式，如果您實作 `RequestHandler` 或 `RequestStreamHandler` 介面，則主要處理常式方法必須命名為 `handleRequest`。此外，請在 `handleRequest` 方法上方加上 `@Override` 標籤。將函式部署到 Lambda 時，請以下列格式在函式的組態中指定主要處理常式：
+ *<package>*.*<Class>* – 例如 `example.OrderHandler`。

對於 Java 中未實作 `RequestHandler` 或 `RequestStreamHandler` 介面的 Lambda 函式，您可以將處理常式命名為任何名稱。將函式部署到 Lambda 時，請以下列格式在函式的組態中指定主要處理常式：
+ *<package>*.*<Class>*::*<handler\$1method\$1name>* – 例如 `example.Handler::mainHandler`。

## 定義和存取輸入事件物件
<a name="java-handler-input"></a>

JSON 是 Lambda 函數最常見的標準輸入格式。在此範例中，函數預期輸入類似以下內容：

```
{
    "orderId": "12345",
    "amount": 199.99,
    "item": "Wireless Headphones"
}
```

使用 Java 17 或更新版本開發 Lambda 函式時，可將預期輸入事件的結構定義為 Java 記錄。在此範例中，我們定義了 `OrderHandler` 類別中的一條記錄來代表 `Order` 物件：

```
public record Order(String orderId, double amount, String item) {}
```

該記錄符合預期的輸入結構。定義記錄之後，您即可編寫處理常式簽章，其會接收符合該記錄定義的 JSON 輸入。Java 執行時期會自動將此 JSON 反序列化為 Java 物件。然後，您可以存取該物件的欄位。例如，使用 `orderId` 可以從原始輸入擷取 `event.orderId` 的值。

**注意**  
僅 Java 17 及更新版本的執行時期支援 Java 記錄功能。在所有 Java 執行期中，可以使用類別來表示事件資料。在此類案例中，您可以使用 [jackson](https://github.com/FasterXML/jackson) 之類的程式庫來反序列化 JSON 輸入。

### 其他輸入事件類型
<a name="java-input-event-types"></a>

Java 中的 Lambda 函式支援多種可能的輸入事件：
+ `Integer` `Long`、`Double`、等等 - 事件是沒有其他格式的數字，例如 `3.5`。Java 執行時期會將值轉換為指定類型的物件。
+ `String` - 事件是 JSON 字串，包括引號，例如 。`“My string”`執行時期會將值轉換為不含引號的 `String` 物件。
+ `List<Integer>` `List<String>`、`List<Object>`、等等 - 該事件是一個 JSON 陣列。執行階段會將它還原序列化為指定類型或介面的物件。
+ `InputStream` - 該事件是任何 JSON 類型。執行階段會將文件的位元組串流傳遞給處理常式而不進行修改。您還原序列化輸入和並將輸出寫入輸出串流。
+ 程式庫類型 – 對於由其他 AWS 服務傳送的事件，請使用 [aws-lambda-java-events](https://github.com/aws/aws-lambda-java-libs/tree/main/aws-lambda-java-events) 程式庫中的類型。例如，若 Amazon Simple Queue Service (SQS) 調用您的 Lambda 函式，則以 `SQSEvent` 物件作為輸入。

## 存取和使用 Lambda 內容物件
<a name="java-example-context"></a>

Lambda [內容物件](java-context.md) 包含有關調用、函數以及執行環境的資訊。在此範例中，內容物件的類型為 `com.amazonaws.services.lambda.runtime.Context`，並且內容物件也是主要處理常式函式的第二個引數。

```
public String handleRequest(Order event, Context context) {
    ...
}
```

如果您的類別實作了 [ RequestHandler](https://github.com/aws/aws-lambda-java-libs/blob/master/aws-lambda-java-core/src/main/java/com/amazonaws/services/lambda/runtime/RequestHandler.java) 或 [ RequestStreamHandler](https://github.com/aws/aws-lambda-java-libs/blob/master/aws-lambda-java-core/src/main/java/com/amazonaws/services/lambda/runtime/RequestStreamHandler.java) 介面，則內容物件為必要引數。否則，內容物件為選用引數。如需有關可接受的有效處理常式簽章的詳細資訊，請參閱 [Java 處理常式的有效類別定義](#java-handler-signatures)。

如果您使用 AWS SDK 呼叫其他服務，則有幾個關鍵區域需要內容物件。例如，若要為 Amazon CloudWatch 生成函式日誌，您可以使用 `context.getLogger()` 方法取得用於記錄的 `LambdaLogger` 物件。在此範例中，如果處理因任何原因失敗，我們可以使用記錄器來記錄錯誤訊息：

```
context.getLogger().log("Failed to process order: " + e.getMessage());
```

除了記錄日誌之外，您還可以將內容物件用於函式監控。如需內容物件的詳細資訊，請參閱[使用 Lambda 內容物件擷取 Java 函數資訊](java-context.md)。

## 在處理常式中使用適用於 Java v2 的 AWS SDK
<a name="java-example-sdk-usage"></a>

通常，您會使用 Lambda 函式與其他 AWS 資源互動或對其進行更新。與這些資源互動的最簡單方法便是使用適用於 Java v2 的 AWS SDK。

**注意**  
適用於 Java (v1) 的 AWS SDK 目前處於維護模式，將於 2025 年 12 月 31 日停止支援。建議今後僅使用適用於 Java v2 的 AWS SDK。

若要將 SDK 相依項新增至函式，請在適用於 Gradle 的 `build.gradle` 檔案或適用於 Maven 的 `pom.xml` 檔案中納入這些相依項。建議僅新增函式所需的程式庫。在先前的範例程式碼中，我們使用了 `software.amazon.awssdk.services.s3` 程式庫。在 Gradle 中，您可以透過在 `build.gradle` 的相依項區段中新增以下一行程式碼來新增此相依項：

```
implementation 'software.amazon.awssdk:s3:2.28.29'
```

在 Maven 中，在 `pom.xml` 的 `<dependencies>` 區段中新增以下程式碼行：

```
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>s3</artifactId>
        <version>2.28.29</version>
    </dependency>
```

**注意**  
SDK 可能不是最新版本。請為應用程式選擇適當的 SDK 版本。

然後，直接在 Java 類別中匯入相依項：

```
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.model.S3Exception;
```

隨後，範例程式碼會初始化 Amazon S3 用戶端，如下所示：

```
private static final S3Client S3_CLIENT = S3Client.builder().build();
```

在此範例中，我們在主要處理常式函式外部初始化 Amazon S3 用戶端，以免每次調用函式時都必須初始化該用戶端。初始化 SDK 用戶端之後，您即可用其與其他 AWS 服務互動。此範例程式碼會呼叫 Amazon S3 `PutObject` API，如下所示：

```
PutObjectRequest putObjectRequest = PutObjectRequest.builder()
    .bucket(bucketName)
    .key(key)
    .build();

// Convert the receipt content to bytes and upload to S3
S3_CLIENT.putObject(putObjectRequest, RequestBody.fromBytes(receiptContent.getBytes(StandardCharsets.UTF_8)));
```

## 存取環境變數
<a name="java-example-envvars"></a>

在處理常式程式碼中，您可以使用 `System.getenv()` 方法來引用任何[環境變數](configuration-envvars.md)。在此範例中，我們使用以下程式碼來參考定義的 `RECEIPT_BUCKET` 環境變數：

```
String bucketName = System.getenv("RECEIPT_BUCKET");
if (bucketName == null || bucketName.isEmpty()) {
    throw new IllegalArgumentException("RECEIPT_BUCKET environment variable is not set");
}
```

## 使用全域狀態
<a name="java-handler-state"></a>

在首次調用函數之前，Lambda 會在[初始化階段](lambda-runtime-environment.md#runtimes-lifecycle-ib)執行靜態程式碼和類別建構函數。在初始化期間建立的資源會在調用間隔期間保留在記憶體中，無需您在每次調用函式時都建立這些資源。

在範例程式碼中，S3 用戶端初始化程式碼位於主要處理常式方法外部。執行時期會在函式處理第一個事件之前初始化用戶端，且用戶端在所有調用中均可供重複使用。

## Java Lambda 函數的程式碼最佳實務
<a name="java-best-practices"></a>

請遵循下列清單中的準則，在建置 Lambda 函數時使用最佳編碼實務：
+ **區隔 Lambda 處理常式與您的核心邏輯。**能允許您製作更多可測單位的函式。
+ **控制函數部署套件內的相依性。**AWS Lambda 執行環境包含多個程式庫。若要啟用最新的一組功能與安全更新，Lambda 會定期更新這些程式庫。這些更新可能會為您的 Lambda 函數行為帶來細微的變更。若要完全掌控您函式所使用的相依性，請利用部署套件封裝您的所有相依性。
+ **最小化依存項目的複雜性。**偏好更簡易的框架，其可快速在[執行環境](lambda-runtime-environment.md)啟動時載入。例如，偏好更簡易的 Java 相依性置入 (IoC) 架構如 [Dagger](https://google.github.io/dagger/) 或 [Guice](https://github.com/google/guice)，勝於複雜的架構如 [Spring Framework](https://github.com/spring-projects/spring-framework)。
+ **將部署套件最小化至執行時期所必要的套件大小。**這能減少您的部署套件被下載與呼叫前解壓縮的時間。對於以 Java 撰寫的函數，請避免上傳整個 AWS SDK 程式庫做為部署套件的一部分。或者，選擇性倚賴取得您需要的軟體開發套件元件的模組 (例如 DynamoDB、Amazon S3 開發套件模組，以及 [Lambda 核心程式庫](https://github.com/aws/aws-lambda-java-libs))。

**請利用執行環境重新使用來改看函式的效能。**在函式處理常式之外初始化 SDK 用戶端和資料庫連線，並在本機快取 `/tmp` 目錄中的靜態資產。由您函式的相同執行個體處理的後續叫用可以重複使用這些資源。這可藉由減少函數執行時間來節省成本。

若要避免叫用間洩漏潛在資料，請不要使用執行環境來儲存使用者資料、事件，或其他牽涉安全性的資訊。如果您的函式依賴無法存放在處理常式內記憶體中的可變狀態，請考慮為每個使用者建立個別函式或個別函式版本。

**使用 Keep-Alive 指令維持持續連線的狀態。**Lambda 會隨著時間的推移清除閒置連線。叫用函數時嘗試重複使用閒置連線將導致連線錯誤。若要維護持續連線，請使用與執行階段相關聯的 keep-alive (保持啟用) 指令。如需範例，請參閱[在 Node.js 中重複使用 Keep-Alive 的連線](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/node-reusing-connections.html)。

**使用[環境變數](configuration-envvars.md)將操作參數傳遞給您的函數。**例如，如果您正在寫入到 Amazon S3 儲存貯體，而非對您正在寫入的儲存貯體名稱進行硬式編碼，請將儲存貯體名稱設定為環境變數。

**避免在 Lambda 函數中使用遞迴調用**，其中函數會調用自己或啟動可能再次調用函數的程序。這會導致意外的函式呼叫量與升高的成本。若您看到意外的調用數量，當更新程式碼時，請立刻將函數的預留並行設為 `0`，以調節對函數的所有調用。

**請勿在您的 Lambda 函數程式碼中使用未記錄的非公有 API**。對於 AWS Lambda 受管執行時間，Lambda 會定期將安全性和函數更新套用至 Lambda 的內部 API。這些內部 API 更新可能是向後不相容的，這會導致意外結果，例如若您的函數依賴於這些非公有 API，則叫用失敗。請參閱 [API 參考](https://docs.aws.amazon.com/lambda/latest/api/welcome.html)查看公開可用 API 的清單。

**撰寫等冪程式碼。**為函數撰寫等冪程式碼可確保採用相同方式來處理重複事件。程式碼應正確驗證事件並正常處理重複的事件。如需詳細資訊，請參閱 [How do I make my Lambda function idempotent?](https://aws.amazon.com/premiumsupport/knowledge-center/lambda-function-idempotent/) (如何讓 Lambda 函數等冪？)。
+ **避免使用 Java DNS 快取。**Lambda 函數已快取 DNS 回應。如果您使用其他 DNS 快取，則可能會發生連線逾時。

  `java.util.logging.Logger` 類別可以間接啟用 JVM DNS 快取。若要覆寫預設設定，請先將 [networkaddress.cache.ttl](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/net/InetAddress.html#inetaddress-caching-heading) 設定為 0，再初始化 `logger`。範例：

  ```
  public class MyHandler {
    // first set TTL property
    static{
     java.security.Security.setProperty("networkaddress.cache.ttl" , "0");
    }
   // then instantiate logger
    var logger = org.apache.logging.log4j.LogManager.getLogger(MyHandler.class);
  }
  ```
+ 將相依性 `.jar` 檔案置於不同的 /lib 目錄，**縮短 Lambda 解壓縮以 Java 撰寫之部署套件的時間**。這比將您所有函式程式碼全部放入具大量 `.class` 檔案的單一 jar 更快速。如需說明，請參閱 [使用 .zip 或 JAR 封存檔部署 Java Lambda 函數](java-package.md)。

# 使用 .zip 或 JAR 封存檔部署 Java Lambda 函數
<a name="java-package"></a>

 AWS Lambda 函數的程式碼包含指令碼或編譯的程式及其相依性。使用*部署套件*將函數程式碼部署到 Lambda。Lambda 支援兩種類型的部署套件：容器映像和 .zip 封存檔。

此頁面說明如何將部署套件建立為 .zip 檔案或 Jar 檔案，然後使用部署套件， AWS Lambda 使用 AWS Command Line Interface (AWS CLI) 將函數程式碼部署至 。

**重要**  
Java 25 引進Ahead-of-Time(AOT) 快取的支援。強烈建議在將函數部署為 .zip 或 JAR 檔案封存時不要使用 AOT 快取，因為當 Lambda 更新受管執行時間時，快取可能會導致非預期的行為。如需詳細資訊，請參閱 [Ahead-of-Time(AOT) 和 CDS 快取](java-customization.md#aot-cds-caches)。

**Topics**
+ [先決條件](#java-package-prereqs)
+ [工具與程式庫](#java-package-libraries)
+ [使用 Gradle 建立部署套件](#java-package-gradle)
+ [使用層來管理相依項](#java-package-layers)
+ [使用 Maven 建立部署套件](#java-package-maven)
+ [使用 Lambda 主控台上傳部署套件](#java-package-console)
+ [使用 上傳部署套件 AWS CLI](#java-package-cli)
+ [使用 上傳部署套件 AWS SAM](#java-package-cloudformation)

## 先決條件
<a name="java-package-prereqs"></a>

 AWS CLI 是一種開放原始碼工具，可讓您使用命令列 Shell 中的 命令與 AWS 服務互動。若要完成本節中的步驟，您必須擁有 [AWS CLI 版本 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)。

## 工具與程式庫
<a name="java-package-libraries"></a>

AWS 為 Java 函數提供下列程式庫。這些程式庫可透過 [Maven Central Repository](https://search.maven.org/search?q=g:com.amazonaws) 取得。
+ [com.amazonaws:aws-lambda-java-core](https://github.com/aws/aws-lambda-java-libs/tree/master/aws-lambda-java-core) (必要) - 定義處理常式方法介面，以及執行期傳遞給處理常式的內容物件。如果您定義自己的輸入類型，這是您需要的唯一程式庫。
+ [com.amazonaws:aws-lambda-java-events](https://github.com/aws/aws-lambda-java-libs/tree/master/aws-lambda-java-events) - 來自調用 Lambda 函數的服務的輸入事件類型。
+ [com.amazonaws:aws-lambda-java-log4j2](https://github.com/aws/aws-lambda-java-libs/tree/master/aws-lambda-java-log4j2) - 一個 Apache Log4j 2 的附加程式庫，您可以使用它將當前調用的請求 ID 新增至[函數日誌](java-logging.md)。
+ [AWS 適用於 Java 的 SDK 2.0](https://github.com/aws/aws-sdk-java-v2) – 適用於 Java 程式設計語言的官方 AWS SDK。

請將這些程式庫新增至建置定義中，如下所示：

------
#### [ Gradle ]

```
dependencies {
    implementation 'com.amazonaws:aws-lambda-java-core:1.2.2'
    implementation 'com.amazonaws:aws-lambda-java-events:3.11.1'
    runtimeOnly 'com.amazonaws:aws-lambda-java-log4j2:1.5.1'
}
```

------
#### [ Maven ]

```
  <dependencies>
    <dependency>
      <groupId>com.amazonaws</groupId>
      <artifactId>aws-lambda-java-core</artifactId>
      <version>1.2.2</version>
    </dependency>
    <dependency>
      <groupId>com.amazonaws</groupId>
      <artifactId>aws-lambda-java-events</artifactId>
      <version>3.11.1</version>
    </dependency>
    <dependency>
      <groupId>com.amazonaws</groupId>
      <artifactId>aws-lambda-java-log4j2</artifactId>
      <version>1.5.1</version>
    </dependency>
  </dependencies>
```

------

若要建立部署套件，請將函數程式碼和相依性編譯成單一 .zip 檔案或 Java 封存 (JAR) 檔案。針對 Gradle，[請使用`Zip`建置類型](#java-package-gradle)。針對 Apache Maven，[請使用 Maven Shade 外掛程式](#java-package-maven)。若要上傳部署套件，請使用 Lambda 主控台、Lambda API 或 AWS Serverless Application Model (AWS SAM)。

**注意**  
若要將您部署套件大小保持較小，請以階層方式將您的函式相依項目進行封裝。各層可讓您獨立管理相依項目，並可供多個函數使用，也可和其他帳戶共用。如需詳細資訊，請參閱[使用層管理 Lambda 相依項](chapter-layers.md)。

## 使用 Gradle 建立部署套件
<a name="java-package-gradle"></a>

若要在 Gradle 中建立具有函數程式碼和相依項的部署套件，請使用 `Zip` 建置類型。以下是[完整的範本 build.gradle 檔案](https://github.com/awsdocs/aws-lambda-developer-guide/blob/main/sample-apps/s3-java/build.gradle)的範例：

**Example build.gradle - 建置任務**  

```
task buildZip(type: Zip) {
    into('lib') {
        from(jar)
        from(configurations.runtimeClasspath)
    }
}
```

此建置組態會在 `build/distributions` 目錄中產生部署套件。在 `into('lib')` 陳述式中，`jar` 任務會將包含主要類別的 JAR 封存檔組合至名稱為 `lib` 的資料夾中。此外，`configurations.runtimeClassPath` 任務會將相依項程式庫從建置的類別路徑複製到名稱為 `lib` 的資料夾中。

**Example 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 檔案包含相同類別，則會使用第一個 JAR。您可以使用以下 shell 指令碼來識別重複的類別︰

**Example 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
```

## 使用層來管理相依項
<a name="java-package-layers"></a>

您可以將函式的相依項封裝為層，使部署套件保持較小體積，獨立管理相依項。如需詳細資訊，請參閱[使用 Java Lambda 函數的層](java-layers.md)。

## 使用 Maven 建立部署套件
<a name="java-package-maven"></a>

要使用 Maven 建置部署套件，請使用 [Maven Shade 外掛程式](https://maven.apache.org/plugins/maven-shade-plugin/)。該外掛程式會建立一個 JAR 檔案，其中包含編譯的函數代碼及其所有相依性。

**Example 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)](https://openjdk.org/jeps/238)，則必須在 `lib` 目錄中包含 MRJAR (即由 Maven Shade 外掛程式產生的陰影 JAR)，並在將部署套件上傳到 Lambda 之前對其進行壓縮。否則，Lambda 可能無法正確解壓縮 JAR 檔案，導致您的 `MANIFEST.MF` 檔案被忽略。

如果您使用附加器程式庫 (`aws-lambda-java-log4j2`)，則還必須配置 Maven Shade 外掛程式的轉換器。轉換器程式庫會合併出現在附加器程式庫和 Log4j 中快取檔案的版本。

**Example pom.xml - 具備 Log4j 2 附加器的外掛程式組態**  

```
      <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 主控台上傳部署套件
<a name="java-package-console"></a>

 若要建立新函數，您必須先在主控台中建立函數，然後上傳您的 .zip 或 JAR 檔案。若要更新現有函數，請開啟函數的頁面，然後按照同樣的程序新增更新後的 .zip 或 JAR 檔案。

 如果您的部署套件檔案小於 50 MB，您可以透過直接從本機電腦上傳檔案來建立或更新函數。若 .zip 或 JAR 檔案大於 50 MB，您必須先將套件上傳至 Amazon S3 儲存貯體。如需如何使用 將檔案上傳至 Amazon S3 儲存貯體的說明 AWS 管理主控台，請參閱 [Amazon S3 入門](https://docs.aws.amazon.com/AmazonS3/latest/userguide/GetStartedWithS3.html)。若要使用 上傳檔案 AWS CLI，請參閱*AWS CLI 《 使用者指南*》中的[移動物件](https://docs.aws.amazon.com/cli/latest/userguide/cli-services-s3-commands.html#using-s3-commands-managing-objects-move)。

**注意**  
不能變更現有函數的[部署套件類型](https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html#lambda-CreateFunction-request-PackageType) (.zip 或容器映像)。例如，您不能轉換容器映像函數以使用 .zip 封存檔。您必須建立新的函數。

**若要建立新的函數 (主控台)**

1. 開啟 Lambda 主控台的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)，然後選擇**建立函數**。

1. 選擇 **Author from scratch** (從頭開始撰寫)。

1. 在**基本資訊**下，請執行下列動作：

   1. 在**函數名稱**中輸入函數名稱。

   1. 在**執行期**中選取要使用的執行期。

   1. (選用) 在**架構**中選擇要用於函數的指令集架構。預設架構值為 x86\$164。請確定函數的 .zip 部署套件與您選取的指令集架構相容。

1. (選用) 在**許可**下，展開**變更預設執行角色**。您可建立新的**執行角色**，或使用現有的角色。

1. 選擇 **Create function (建立函數)**。Lambda 會使用您選擇的執行期建立一個基本的「Hello world」函數。

**若要從本機電腦上傳 .zip 或 JAR 封存檔 (主控台)**

1. 在 Lambda 主控台的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)中選擇要上傳 .zip 或 JAR 檔案的函數。

1. 選取**程式碼**索引標籤。

1. 在**程式碼來源**窗格中選擇**上傳來源**。

1. 選擇 **.zip 或 .jar 檔案**。

1. 若要上傳 .zip 或 JAR 檔案，請執行下列操作：

   1. 選取**上傳**，然後在檔案選擇器中選取您的 .zip 或 JAR 檔案。

   1. 選擇 **Open** (開啟)。

   1. 選擇**儲存**。

**若要從 Amazon S3 儲存貯體上傳 .zip 或 JAR 封存檔 (控制台)**

1. 在 Lambda 主控台的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)中選擇要上傳新 .zip 或 JAR 檔案的函數。

1. 選取**程式碼**索引標籤。

1. 在**程式碼來源**窗格中選擇**上傳來源**。

1. 選擇 **Amazon S3 位置**。

1. 貼上 .zip 檔案的 Amazon S3 連結 URL，然後選擇**儲存**。

## 使用 上傳部署套件 AWS CLI
<a name="java-package-cli"></a>

 您可以使用 [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) 建立新函數，或使用 .zip 或 JAR 檔案更新現有函數。使用 [create-function](https://docs.aws.amazon.com/cli/latest/reference/lambda/create-function.html) 和 [update-function-code](https://docs.aws.amazon.com/cli/latest/reference/lambda/create-function.html) 命令來部署您的 .zip 或 JAR 套件。如果您的檔案小於 50 MB，則可以從本機建置電腦的檔案位置上傳套件。若檔案較大，則必須先從 Amazon S3 儲存貯體上傳 .zip 或 JAR 套件。如需如何使用 將檔案上傳至 Amazon S3 儲存貯體的指示 AWS CLI，請參閱*AWS CLI 《 使用者指南*》中的[移動物件](https://docs.aws.amazon.com/cli/latest/userguide/cli-services-s3-commands.html#using-s3-commands-managing-objects-move)。

**注意**  
如果您使用 從 Amazon S3 儲存貯體上傳 .zip 或 JAR 檔案 AWS CLI，則儲存貯體必須與 AWS 區域 函數位於相同的 中。

 若要使用 .zip 或 JAR 檔案搭配 建立新的函數 AWS CLI，您必須指定下列項目：
+ 函數名稱 (`--function-name`)
+ 函數的執行期 (`--runtime`)
+ 函數[執行角色](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html)的 Amazon Resource Name (ARN) (`--role`)
+ 函數程式碼中處理常式方法的名稱 (`--handler`)

 您也必須指定 .zip 或 JAR 檔案的位置。如果您的 .zip 或 JAR 檔案位於本機建置電腦上的資料夾中，請使用 `--zip-file` 選項來指定檔案路徑，如下列範例命令所示。

```
aws lambda create-function --function-name myFunction \
--runtime java25 --handler example.handler \
--role arn:aws:iam::123456789012:role/service-role/my-lambda-role \
--zip-file fileb://myFunction.zip
```

 若要在 Amazon S3 儲存貯體中指定 .zip 檔案的位置，請使用如下列範例命令所示的 `--code` 選項。您只需針對版本控制的物件使用 `S3ObjectVersion` 參數。

```
aws lambda create-function --function-name myFunction \
--runtime java25 --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
```

 若要在 Amazon S3 儲存貯體中指定 .zip 檔案的位置，請使用如下列範例命令所示的 `--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
<a name="java-package-cloudformation"></a>

您可以使用 AWS SAM 自動部署函數程式碼、組態和相依性。 AWS SAM 是 的延伸 CloudFormation ，提供定義無伺服器應用程式的簡化語法。下列範例範本會透過在 Gradle 使用的 `build/distributions` 目錄中的部署套件定義函數︰

**Example 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](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html)
    Properties:
      CodeUri: build/distributions/java-basic.zip
      Handler: example.Handler
      Runtime: java25
      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 建置並上傳到它建立的部署套件。它會在您第一次執行 CloudFormation 堆疊時建立堆疊。如果堆疊已存在，則指令碼會加以更新。

**Example 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 應用程式**
+ [example-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/example-java) – Java 函式，示範如何使用 Lambda 處理訂單。此函數說明如何定義和還原序列化自訂輸入事件物件、使用 AWS SDK 和輸出記錄。
+ [java-basic](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-basic) - 具有單元測試和變數日誌組態的最小 Java 函數集合。
+ [java-events](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-events) - Java 函數集合，其中包含如何處理來自各種服務 (例如 Amazon API Gateway、Amazon SQS 和 Amazon Kinesis) 事件的骨架程式碼。這些函數使用最新版 [aws-lambda-java-events](#java-package) 程式庫 (3.0.0 及更新版)。這些範例不需要 AWS SDK 做為相依性。
+ [s3-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/s3-java) - 一種 Java 函數，它處理來自 Amazon S3 的通知事件，並使用 Java Class Library (JCL) 以從上傳的映像檔案建立縮圖。
+ [layer-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/layer-java) – 此 Java 函式示範如何使用 Lambda 層，將相依項與核心函式程式碼分離封裝。

# 使用容器映像部署 Java Lambda 函數
<a name="java-image"></a>

您可以透過三種方式為 Java Lambda 函數建置容器映像：
+ [使用 Java AWS 的基礎映像](#java-image-instructions)

  [AWS  基礎映像](images-create.md#runtimes-images-lp)會預先載入語言執行期、用來管理 Lambda 與函數程式碼之間互動的執行期界面用戶端，以及用於本機測試的執行期界面模擬器。
+ [使用僅限 AWS 作業系統的基礎映像](images-create.md#runtimes-images-provided)

  [AWS 僅限作業系統的基礎映像](https://gallery.ecr.aws/lambda/provided)包含 Amazon Linux 發行版本和[執行時間界面模擬器](https://github.com/aws/aws-lambda-runtime-interface-emulator/)。這些映像常用於為編譯語言 (如 [Go](go-image.md#go-image-provided) 和 [Rust](lambda-rust.md)) 和 Lambda 不提供基礎映像的語言或語言版本 (如 Node.js 19) 建置容器映像。您還可以使用僅限作業系統的基礎映像來實作[自訂執行期](runtimes-custom.md)。若要使映像與 Lambda 相容，您必須在映像中加入[適用於 Java 的執行期介面用戶端](#java-image-clients)。
+ [使用非AWS 基礎映像](#java-image-clients)

  您可以使用其他容器登錄檔中的替代基礎映像 (例如 Alpine Linux 或 Debian)。您也可以使用組織建立的自訂映像。若要使映像與 Lambda 相容，您必須在映像中加入[適用於 Java 的執行期介面用戶端](#java-image-clients)。

**提示**  
若要縮短 Lambda 容器函數變成作用中狀態所需的時間，請參閱 Docker 文件中的[使用多階段建置](https://docs.docker.com/build/building/multi-stage/)。若要建置有效率的容器映像，請遵循[撰寫 Dockerfiles 的最佳實務](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)。

本頁面會說明如何為 Lambda 建置、測試和部署容器映像。

**Topics**
+ [AWS Java 的基礎映像](#java-image-base)
+ [使用 Java AWS 的基礎映像](#java-image-instructions)
+ [透過執行期介面用戶端使用替代基礎映像](#java-image-clients)

## AWS Java 的基礎映像
<a name="java-image-base"></a>

AWS 為 Java 提供下列基礎映像：


| Tags (標籤) | 執行期 | 作業系統 | Dockerfile | 棄用 | 
| --- | --- | --- | --- | --- | 
| 25 | Java 25 | Amazon Linux 2023 | [GitHub 上適用於 Java 25 的 Dockerfile](https://github.com/aws/aws-lambda-base-images/blob/java25/Dockerfile.java25) |   2029 年 6 月 30 日   | 
| 21 | Java 21 | Amazon Linux 2023 | [Dockerfile for Java 21 on GitHub](https://github.com/aws/aws-lambda-base-images/blob/java21/Dockerfile.java21) |   2029 年 6 月 30 日   | 
| 17 | Java 17 | Amazon Linux 2 | [Dockerfile for Java 17 on GitHub](https://github.com/aws/aws-lambda-base-images/blob/java17/Dockerfile.java17) |   2027 年 6 月 30 日   | 
| 11 | Java 11 | Amazon Linux 2 | [Dockerfile for Java 11 on GitHub](https://github.com/aws/aws-lambda-base-images/blob/java11/Dockerfile.java11) |   2027 年 6 月 30 日   | 
| 8.al2 | Java 8 | Amazon Linux 2 | [Dockerfile for Java 8 on GitHub](https://github.com/aws/aws-lambda-base-images/blob/java8.al2/Dockerfile.java8.al2) |   2027 年 6 月 30 日   | 

Amazon ECR 儲存庫︰[gallery.ecr.aws/lambda/java](https://gallery.ecr.aws/lambda/java)

Java 21 和更新版本的基礎映像以 [Amazon Linux 2023 最小容器映像](https://docs.aws.amazon.com/linux/al2023/ug/minimal-container.html)為基礎。舊版基礎映像使用 Amazon Linux 2。與 Amazon Linux 2 相比，AL2023 具有多項優點，包括更小的部署足跡和更新版本的程式庫，如 `glibc`。

以 AL2023 為基礎的映像使用 `microdnf` (符號連結為 `dnf`) 而不是 `yum` 作為套件管理工具，後者是 Amazon Linux 2 中的預設套件管理工具。`microdnf` 是 `dnf` 的獨立實作。對於以 AL2023 為基礎的映像中包含的套件清單，請參閱 [Comparing packages installed on Amazon Linux 2023 Container Images](https://docs.aws.amazon.com/linux/al2023/ug/al2023-container-image-types.html) 中的 **Minimal Container** 欄。如需 AL2023 和 Amazon Linux 2 之間差異的詳細資訊，請參閱 AWS 運算部落格上的 [Introducing the Amazon Linux 2023 runtime for AWS Lambda](https://aws.amazon.com/blogs/compute/introducing-the-amazon-linux-2023-runtime-for-aws-lambda/)。

**注意**  
若要在本機執行AL2023-based映像，包括搭配 AWS Serverless Application Model (AWS SAM)，您必須使用 Docker 20.10.10 版或更新版本。

## 使用 Java AWS 的基礎映像
<a name="java-image-instructions"></a>

### 先決條件
<a name="java-image-prerequisites"></a>

若要完成本節中的步驟，您必須執行下列各項：
+ Java (例如，[Amazon Corretto](https://aws.amazon.com/corretto))
+ [Apache Maven](https://maven.apache.org/) 或 [Gradle](https://gradle.org/install/)
+ [AWS CLI 第 2 版](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [Docker](https://docs.docker.com/get-docker) (最低版本 25.0.0)
+ Docker [buildx 外掛程式](https://github.com/docker/buildx/blob/master/README.md)。

### 從基礎映像建立映像
<a name="java-image-create"></a>

------
#### [ Maven ]

1. 執行下列命令，使用 [Lambda 的原型](https://github.com/aws/aws-sdk-java-v2/tree/master/archetypes/archetype-lambda)建立 Maven 專案。下列是必要參數：
   + **服務** – 要在 Lambda 函數中使用的 AWS 服務 用戶端。如需可用來源的清單，請參閱 GitHub 上的 [aws-sdk-java-v2/services](https://github.com/aws/aws-sdk-java-v2/tree/master/services)。
   + **region** – 您要建立 Lambda 函數的 AWS 區域 。
   + **groupId** – 應用程式的完整套件命名空間。
   + **artifactId** – 您的專案名稱。這會成為您專案的目錄名稱。

   在 Linux 和 macOS 中，執行此命令：

   ```
   mvn -B archetype:generate \
      -DarchetypeGroupId=software.amazon.awssdk \
      -DarchetypeArtifactId=archetype-lambda -Dservice=s3 -Dregion=US_WEST_2 \
      -DgroupId=com.example.myapp \
      -DartifactId=myapp
   ```

   在 PowerShell 中，執行此命令：

   ```
   mvn -B archetype:generate `
      "-DarchetypeGroupId=software.amazon.awssdk" `
      "-DarchetypeArtifactId=archetype-lambda" "-Dservice=s3" "-Dregion=US_WEST_2" `
      "-DgroupId=com.example.myapp" `
      "-DartifactId=myapp"
   ```

   Lambda 的 Maven 原型已預先設定為使用 Java SE 8 編譯，並包含對 適用於 Java 的 AWS SDK的相依性。如果您使用不同的原型或使用其他方法來建立專案，則必須[為 Maven 設定 Java 編譯器](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup-project-maven.html#configure-maven-compiler)並[將 SDK 宣告為相依項](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup-project-maven.html#configure-maven-compiler)。

1. 開啟 `myapp/src/main/java/com/example/myapp` 目錄並找到 `App.java` 檔案。這是 Lambda 函數的程式碼。可以使用提供的範本程式碼進行測試，也可以將其替換為您自己的程式碼。

1. 返回專案的根目錄，然後使用以下組態建立新的 Dockerfile：
   + 將 `FROM` 屬性設定為[基礎映像的 URI](https://gallery.ecr.aws/lambda/java)。
   + 將 `CMD` 引數設定為 Lambda 函數處理常式。

   請注意，範例 Dockerfile 不包含 [USER 指令](https://docs.docker.com/reference/dockerfile/#user)。當您將容器映像部署到 Lambda 時，Lambda 會自動定義一個具有最低權限許可的預設 Linux 使用者。這與標準 Docker 行為不同，後者會在未提供 `USER` 指令時預設為 `root` 使用者。  
**Example Dockerfile**  

   ```
   FROM public.ecr.aws/lambda/java:21
     
   # Copy function code and runtime dependencies from Maven layout
   COPY target/classes ${LAMBDA_TASK_ROOT}
   COPY target/dependency/* ${LAMBDA_TASK_ROOT}/lib/
       
   # Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile)
   CMD [ "com.example.myapp.App::handleRequest" ]
   ```

1. 編譯專案並收集執行期相依性。

   ```
   mvn compile dependency:copy-dependencies -DincludeScope=runtime
   ```

1. 使用 [docker build](https://docs.docker.com/engine/reference/commandline/build/) 命令建立 Docker 映像檔。以下範例將映像命名為 `docker-image` 並為其提供 `test` [標籤](https://docs.docker.com/engine/reference/commandline/build/#tag)。若要使映像與 Lambda 相容，必須使用 `--provenance=false` 選項。

   ```
   docker buildx build --platform linux/amd64 --provenance=false -t docker-image:test .
   ```
**注意**  
此命令會指定 `--platform linux/amd64` 選項，確保無論建置機器的架構為何，您的容器都與 Lambda 執行環境相容。如果您打算使用 ARM64 指令集架構建立 Lambda 函數，務必將命令變更為改用 `--platform linux/arm64` 選項。

------
#### [ Gradle ]

1. 建立專案的目錄，然後切換至該目錄。

   ```
   mkdir example
   cd example
   ```

1. 執行以下命令，讓 Gradle 在環境的 `example` 目錄中產生新的 Java 應用程式專案。對於**選取建置指令碼 DSL**，選擇 **2：Groovy**。

   ```
   gradle init --type java-application
   ```

1. 開啟 `/example/app/src/main/java/example` 目錄並找到 `App.java` 檔案。這是 Lambda 函數的程式碼。可以使用以下範本程式碼進行測試，也可以將其替換為您自己的程式碼。  
**Example App.java**  

   ```
   package com.example;
   import com.amazonaws.services.lambda.runtime.Context;
   import com.amazonaws.services.lambda.runtime.RequestHandler;
   public class App implements RequestHandler<Object, String> {
       public String handleRequest(Object input, Context context) {
           return "Hello world!";
       }
   }
   ```

1. 開啟 `build.gradle` 檔案。如果使用上一個步驟的範本函數程式碼，請將 `build.gradle` 的內容替換為下列值。如果使用自己的函數程式碼，則請根據需要修改 `build.gradle` 檔案。  
**Example build.gradle (Groovy DSL)**  

   ```
   plugins {
     id 'java'
   }
   group 'com.example'
   version '1.0-SNAPSHOT'
   sourceCompatibility = 1.8
   repositories {
     mavenCentral()
   }
   dependencies {
     implementation 'com.amazonaws:aws-lambda-java-core:1.2.1'
   }
   jar {
     manifest {
         attributes 'Main-Class': 'com.example.App'
     }
   }
   ```

1. 步驟 2 中的 `gradle init` 命令也在 `app/test` 目錄中產生了一個虛擬測試案例。為實現本教學課程的目的，請刪除 `/test` 目錄，以略過正在執行的測試。

1. 建置專案。

   ```
   gradle build
   ```

1. 在專案的根目錄 (`/example`) 中，使用以下組態建立一個 Dockerfile：
   + 將 `FROM` 屬性設定為[基礎映像的 URI](https://gallery.ecr.aws/lambda/java)。
   + 使用 COPY 命令將函數程式碼和執行時期相依項複製到 `{LAMBDA_TASK_ROOT}`，一個 [Lambda 定義的環境變數](configuration-envvars.md#configuration-envvars-runtime)。
   + 將 `CMD` 引數設定為 Lambda 函數處理常式。

   請注意，範例 Dockerfile 不包含 [USER 指令](https://docs.docker.com/reference/dockerfile/#user)。當您將容器映像部署到 Lambda 時，Lambda 會自動定義一個具有最低權限許可的預設 Linux 使用者。這與標準 Docker 行為不同，後者會在未提供 `USER` 指令時預設為 `root` 使用者。  
**Example Dockerfile**  

   ```
   FROM public.ecr.aws/lambda/java:21
     
   # Copy function code and runtime dependencies from Gradle layout
   COPY app/build/classes/java/main ${LAMBDA_TASK_ROOT}
     
   # Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile)
   CMD [ "com.example.App::handleRequest" ]
   ```

1. 使用 [docker build](https://docs.docker.com/engine/reference/commandline/build/) 命令建立 Docker 映像檔。以下範例將映像命名為 `docker-image` 並為其提供 `test` [標籤](https://docs.docker.com/engine/reference/commandline/build/#tag)。若要使映像與 Lambda 相容，必須使用 `--provenance=false` 選項。

   ```
   docker buildx build --platform linux/amd64 --provenance=false -t docker-image:test .
   ```
**注意**  
此命令會指定 `--platform linux/amd64` 選項，確保無論建置機器的架構為何，您的容器都與 Lambda 執行環境相容。如果您打算使用 ARM64 指令集架構建立 Lambda 函數，務必將命令變更為改用 `--platform linux/arm64` 選項。

------

### (選用) 在本機測試映像
<a name="java-image-test"></a>

1. 使用 **docker run** 命令啟動 Docker 影像。在此範例中，`docker-image` 為映像名稱，`test` 為標籤。

   ```
   docker run --platform linux/amd64 -p 9000:8080 docker-image:test
   ```

   此命令將映像作為容器執行，並在 `localhost:9000/2015-03-31/functions/function/invocations` 建立本機端點。
**注意**  
如果您為 ARM64 指令集架構建立 Docker 映像檔，請務必將`--platform linux/arm64`選項改用選項。`--platform linux/amd64`

1. 從新的終端機視窗，將事件張貼至本機端點。

------
#### [ Linux/macOS ]

   在 Linux 或 macOS 中，執行下列 `curl` 命令：

   ```
   curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
   ```

   此命令會透過空白事件調用函數，並傳回一個回應。如果您使用自己的函數程式碼而不是範例函數程式碼，則可能需要使用 JSON 承載調用該函數。範例：

   ```
   curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"payload":"hello world!"}'
   ```

------
#### [ PowerShell ]

   在 PowerShell 中，執行下列 `Invoke-WebRequest` 命令：

   ```
   Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{}' -ContentType "application/json"
   ```

   此命令會透過空白事件調用函數，並傳回一個回應。如果您使用自己的函數程式碼而不是範例函數程式碼，則可能需要使用 JSON 承載調用該函數。範例：

   ```
   Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{"payload":"hello world!"}' -ContentType "application/json"
   ```

------

1. 取得容器 ID。

   ```
   docker ps
   ```

1. 使用 [docker kill](https://docs.docker.com/engine/reference/commandline/kill/) 命令停止容器。在此命令中，將 `3766c4ab331c` 替換為上一步驟中的容器 ID。

   ```
   docker kill 3766c4ab331c
   ```

### 部署映像
<a name="java-image-deploy"></a>

**若要將映像上傳至 Amazon ECR 並建立 Lambda 函數**

1. 使用 [get-login-password](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ecr/get-login-password.html) 命令，向 Amazon ECR 登錄檔驗證 Docker CLI。
   + 將 `--region`值設定為您要 AWS 區域 在其中建立 Amazon ECR 儲存庫的 。
   + `111122223333` 以您的 AWS 帳戶 ID 取代 。

   ```
   aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 111122223333.dkr.ecr.us-east-1.amazonaws.com
   ```

1. 使用 [create-repository](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ecr/create-repository.html) 命令在 Amazon ECR 中建立儲存庫。

   ```
   aws ecr create-repository --repository-name hello-world --region us-east-1 --image-scanning-configuration scanOnPush=true --image-tag-mutability MUTABLE
   ```
**注意**  
Amazon ECR 儲存庫必須與 Lambda 函數位於相同的 AWS 區域 中。

   如果成功，您將會看到以下回應：

   ```
   {
       "repository": {
           "repositoryArn": "arn:aws:ecr:us-east-1:111122223333:repository/hello-world",
           "registryId": "111122223333",
           "repositoryName": "hello-world",
           "repositoryUri": "111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world",
           "createdAt": "2023-03-09T10:39:01+00:00",
           "imageTagMutability": "MUTABLE",
           "imageScanningConfiguration": {
               "scanOnPush": true
           },
           "encryptionConfiguration": {
               "encryptionType": "AES256"
           }
       }
   }
   ```

1. 從上一步驟的輸出中複製 `repositoryUri`。

1. 執行 [docker tag](https://docs.docker.com/engine/reference/commandline/tag/) 命令，將 Amazon ECR 儲存庫中的本機映像標記為最新版本。在此命令中：
   + `docker-image:test` 為 Docker 映像檔的名稱和[標籤](https://docs.docker.com/engine/reference/commandline/build/#tag)。這是您在 `docker build` 命令中指定的映像名稱和標籤。
   + 將 `<ECRrepositoryUri>` 替換為複製的 `repositoryUri`。確保在 URI 的末尾包含 `:latest`。

   ```
   docker tag docker-image:test <ECRrepositoryUri>:latest
   ```

   範例：

   ```
   docker tag docker-image:test 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
   ```

1. 執行 [docker push](https://docs.docker.com/engine/reference/commandline/push/) 命令，將本機映像部署至 Amazon ECR 儲存庫。確保在儲存庫 URI 的末尾包含 `:latest`。

   ```
   docker push 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
   ```

1. [建立函數的執行角色](lambda-intro-execution-role.md#permissions-executionrole-api) (若您還沒有的話)。在下一個步驟中您需要角色的 Amazon Resource Name (ARN)。

1. 建立 Lambda 函數。對於 `ImageUri`，從之前的設定中指定儲存庫 URI。確保在 URI 的末尾包含 `:latest`。

   ```
   aws lambda create-function \
     --function-name hello-world \
     --package-type Image \
     --code ImageUri=111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest \
     --role arn:aws:iam::111122223333:role/lambda-ex
   ```
**注意**  
只要映像與 Lambda 函數位於相同的區域，您就可以使用不同 AWS 帳戶中的映像來建立函數。如需詳細資訊，請參閱[Amazon ECR 跨帳戶許可](images-create.md#configuration-images-xaccount-permissions)。

1. 調用函數。

   ```
   aws lambda invoke --function-name hello-world response.json
   ```

   您應該看到如下回應：

   ```
   {
     "ExecutedVersion": "$LATEST", 
     "StatusCode": 200
   }
   ```

1. 若要查看函數的輸出，請檢查 `response.json` 檔案。

若要更新函數程式碼，您必須再次建置映像、將新映像上傳到 Amazon ECR 存放庫，然後使用 [update-function-code](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-code.html) 命令將映像部署到 Lambda 函數。

Lambda 會將映像標籤解析為特定映像摘要。這表示如果您將用來部署函數的映像標籤指向 Amazon ECR 中的新映像，Lambda 不會自動更新函數以使用新映像。

若要將新映像部署至相同的 Lambda 函數，必須使用 [update-function-code](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-code.html) 命令，即使 Amazon ECR 中的映像標籤保持不變亦如此。在以下範例中，`--publish` 選項會使用更新的容器映像來建立新的函數版本。

```
aws lambda update-function-code \
  --function-name hello-world \
  --image-uri 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest \
  --publish
```

## 透過執行期介面用戶端使用替代基礎映像
<a name="java-image-clients"></a>

如果您使用[僅限作業系統的基礎映像](images-create.md#runtimes-images-provided)或替代的基礎映像，則必須在映像中加入執行期介面用戶端。執行期介面用戶端會讓您擴充 [Runtime API](runtimes-api.md)，管理 Lambda 與函數程式碼之間的互動。

在 Dockerfile 中安裝適用於 Java 的執行期介面用戶端，或作為專案中的相依項。例如，若要使用 Maven 套件管理員安裝執行期界面用戶端，請將以下內容新增至您的 `pom.xml` 檔案中：

```
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-lambda-java-runtime-interface-client</artifactId>
    <version>2.3.2</version>
</dependency>
```

如需套件詳細資訊，請參閱 Maven Central Repository 中的 [AWS Lambda Java 執行期介面用戶端](https://mvnrepository.com/artifact/com.amazonaws/aws-lambda-java-runtime-interface-client)。您還可以在 [AWS Lambda Java 支援程式庫](https://github.com/aws/aws-lambda-java-libs/tree/main/aws-lambda-java-runtime-interface-client) GitHub 儲存庫中檢閱執行期介面用戶端原始程式碼。

以下範例示範如何使用 [Amazon Corretto 映像](https://gallery.ecr.aws/amazoncorretto/amazoncorretto)為 Java 建置容器映像。Amazon Corretto 是 Open Java Development Kit (OpenJDK) 的免費、多平台的生產就緒分佈。Maven 專案包括執行期介面用戶端作為相依項。

### 先決條件
<a name="java-alt-prerequisites"></a>

若要完成本節中的步驟，您必須執行下列各項：
+ Java (例如，[Amazon Corretto](https://aws.amazon.com/corretto))
+ [Apache Maven](https://maven.apache.org/)
+ [AWS CLI 第 2 版](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [Docker](https://docs.docker.com/get-docker) (最低版本 25.0.0)
+ Docker [buildx 外掛程式](https://github.com/docker/buildx/blob/master/README.md)。

### 使用替代基礎映像建立映像
<a name="java-alt-create"></a>

1. 建立 Maven 專案。下列是必要參數：
   + **groupId** – 應用程式的完整套件命名空間。
   + **artifactId** – 您的專案名稱。這會成為您專案的目錄名稱。

------
#### [ Linux/macOS ]

   ```
   mvn -B archetype:generate \
      -DarchetypeArtifactId=maven-archetype-quickstart \
      -DgroupId=example \
      -DartifactId=myapp \
      -DinteractiveMode=false
   ```

------
#### [ PowerShell ]

   ```
   mvn -B archetype:generate `
      -DarchetypeArtifactId=maven-archetype-quickstart `
      -DgroupId=example `
      -DartifactId=myapp `
      -DinteractiveMode=false
   ```

------

1. 開啟專案目錄。

   ```
   cd myapp
   ```

1. 開啟 `pom.xml` 檔案並將內容替換如下：此檔案包括 [aws-lambda-java-runtime-interface-client](https://github.com/aws/aws-lambda-java-libs/tree/main/aws-lambda-java-runtime-interface-client) 作為相依項。或者，您可以在 Dockerfile 中安裝執行期界面用戶端。不過，最簡單的方法是將程式庫包含為相依項。

   ```
   <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <groupId>example</groupId>
     <artifactId>hello-lambda</artifactId>
     <packaging>jar</packaging>
     <version>1.0-SNAPSHOT</version>
     <name>hello-lambda</name>
     <url>http://maven.apache.org</url>
     <properties>
       <maven.compiler.source>1.8</maven.compiler.source>
       <maven.compiler.target>1.8</maven.compiler.target>
     </properties>
     <dependencies>
       <dependency>
         <groupId>com.amazonaws</groupId>
         <artifactId>aws-lambda-java-runtime-interface-client</artifactId>
         <version>2.3.2</version>
       </dependency>
     </dependencies>
     <build>
       <plugins>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-dependency-plugin</artifactId>
           <version>3.1.2</version>
           <executions>
             <execution>
               <id>copy-dependencies</id>
               <phase>package</phase>
               <goals>
                 <goal>copy-dependencies</goal>
               </goals>
             </execution>
           </executions>
         </plugin>
       </plugins>
     </build>
   </project>
   ```

1. 開啟 `myapp/src/main/java/com/example/myapp` 目錄並找到 `App.java` 檔案。這是 Lambda 函數的程式碼。將程式碼取代為以下內容。  
**Example 函數處理常式**  

   ```
   package example;
   
   public class App {
       public static String sayHello() {
           return "Hello world!";
       }
   }
   ```

1. 步驟 1 中的 `mvn -B archetype:generate` 命令也在 `src/test` 目錄中產生了一個虛擬測試案例。為實現本教學課程的目的，請將整個產生的 `/test` 目錄刪除，以略過執行測試程序。

1. 返回專案的根目錄，然後建立新的 Dockerfile。下列 Dockerfile 範例使用 [Amazon Corretto 映像](https://gallery.ecr.aws/amazoncorretto/amazoncorretto)。Amazon Corretto 是 OpenJDK 的免費、多平台的生產就緒分佈。
   + 將 `FROM` 屬性設定為基礎映像的 URI。
   + 將 `ENTRYPOINT` 設為您希望 Docker 容器在啟動時執行的模組。在此案例中，模組是執行期界面用戶端。
   + 將 `CMD` 引數設定為 Lambda 函數處理常式。

   請注意，範例 Dockerfile 不包含 [USER 指令](https://docs.docker.com/reference/dockerfile/#user)。當您將容器映像部署到 Lambda 時，Lambda 會自動定義一個具有最低權限許可的預設 Linux 使用者。這與標準 Docker 行為不同，後者會在未提供 `USER` 指令時預設為 `root` 使用者。  
**Example Dockerfile**  

   ```
   FROM public.ecr.aws/amazoncorretto/amazoncorretto:21 as base
   
   # Configure the build environment
   FROM base as build
   RUN yum install -y maven
   WORKDIR /src
   
   # Cache and copy dependencies
   ADD pom.xml .
   RUN mvn dependency:go-offline dependency:copy-dependencies
   
   # Compile the function
   ADD . .
   RUN mvn package 
   
   # Copy the function artifact and dependencies onto a clean base
   FROM base
   WORKDIR /function
   
   COPY --from=build /src/target/dependency/*.jar ./
   COPY --from=build /src/target/*.jar ./
   
   # Set runtime interface client as default command for the container runtime
   ENTRYPOINT [ "/usr/bin/java", "-cp", "./*", "com.amazonaws.services.lambda.runtime.api.client.AWSLambda" ]
   # Pass the name of the function handler as an argument to the runtime
   CMD [ "example.App::sayHello" ]
   ```

1. 使用 [docker build](https://docs.docker.com/engine/reference/commandline/build/) 命令建立 Docker 映像檔。以下範例將映像命名為 `docker-image` 並為其提供 `test` [標籤](https://docs.docker.com/engine/reference/commandline/build/#tag)。若要使映像與 Lambda 相容，必須使用 `--provenance=false` 選項。

   ```
   docker buildx build --platform linux/amd64 --provenance=false -t docker-image:test .
   ```
**注意**  
此命令會指定 `--platform linux/amd64` 選項，確保無論建置機器的架構為何，您的容器都與 Lambda 執行環境相容。如果您打算使用 ARM64 指令集架構建立 Lambda 函數，務必將命令變更為改用 `--platform linux/arm64` 選項。

### (選用) 在本機測試映像
<a name="java-alt-test"></a>

使用 [執行期界面模擬器](https://github.com/aws/aws-lambda-runtime-interface-emulator/) 以在本機測試映像。您可以[將模擬器建置到映像中](https://github.com/aws/aws-lambda-runtime-interface-emulator/?tab=readme-ov-file#build-rie-into-your-base-image)，也可以使用以下步驟，將其安裝在本機電腦。

**若要在本機電腦上安裝並執行執行期介面模擬器**

1. 在您的專案目錄中執行以下命令，從 GitHub 下載執行期介面模擬器 (x86-64 架構)，並安裝在本機電腦上。

------
#### [ Linux/macOS ]

   ```
   mkdir -p ~/.aws-lambda-rie && \
       curl -Lo ~/.aws-lambda-rie/aws-lambda-rie https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie && \
       chmod +x ~/.aws-lambda-rie/aws-lambda-rie
   ```

   若要安裝 arm64 模擬器，請將上一個命令中的 GitHub 儲存庫 URL 替換為以下內容：

   ```
   https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie-arm64
   ```

------
#### [ PowerShell ]

   ```
   $dirPath = "$HOME\.aws-lambda-rie"
   if (-not (Test-Path $dirPath)) {
       New-Item -Path $dirPath -ItemType Directory
   }
         
   $downloadLink = "https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie"
   $destinationPath = "$HOME\.aws-lambda-rie\aws-lambda-rie"
   Invoke-WebRequest -Uri $downloadLink -OutFile $destinationPath
   ```

   若要安裝 arm64 模擬器，請將 `$downloadLink` 更換為下列項目：

   ```
   https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie-arm64
   ```

------

1. 使用 **docker run** 命令啟動 Docker 影像。注意下列事項：
   + `docker-image` 是映像名稱，而 `test` 是標籤。
   + `/usr/bin/java -cp './*' com.amazonaws.services.lambda.runtime.api.client.AWSLambda example.App::sayHello` 是 Dockerfile 中的 `ENTRYPOINT`，後面接著 `CMD`。

------
#### [ Linux/macOS ]

   ```
   docker run --platform linux/amd64 -d -v ~/.aws-lambda-rie:/aws-lambda -p 9000:8080 \
       --entrypoint /aws-lambda/aws-lambda-rie \
       docker-image:test \
           /usr/bin/java -cp './*' com.amazonaws.services.lambda.runtime.api.client.AWSLambda example.App::sayHello
   ```

------
#### [ PowerShell ]

   ```
   docker run --platform linux/amd64 -d -v "$HOME\.aws-lambda-rie:/aws-lambda" -p 9000:8080 `
   --entrypoint /aws-lambda/aws-lambda-rie `
   docker-image:test `
       /usr/bin/java -cp './*' com.amazonaws.services.lambda.runtime.api.client.AWSLambda example.App::sayHello
   ```

------

   此命令將映像作為容器執行，並在 `localhost:9000/2015-03-31/functions/function/invocations` 建立本機端點。
**注意**  
如果您為 ARM64 指令集架構建立 Docker 映像檔，請務必將`--platform linux/arm64`選項改用選項。`--platform linux/amd64`

1. 將事件張貼至本機端點。

------
#### [ Linux/macOS ]

   在 Linux 或 macOS 中，執行下列 `curl` 命令：

   ```
   curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
   ```

   此命令會透過空白事件調用函數，並傳回一個回應。如果您使用自己的函數程式碼而不是範例函數程式碼，則可能需要使用 JSON 承載調用該函數。範例：

   ```
   curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"payload":"hello world!"}'
   ```

------
#### [ PowerShell ]

   在 PowerShell 中，執行下列 `Invoke-WebRequest` 命令：

   ```
   Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{}' -ContentType "application/json"
   ```

   此命令會透過空白事件調用函數，並傳回一個回應。如果您使用自己的函數程式碼而不是範例函數程式碼，則可能需要使用 JSON 承載調用該函數。範例：

   ```
   Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{"payload":"hello world!"}' -ContentType "application/json"
   ```

------

1. 取得容器 ID。

   ```
   docker ps
   ```

1. 使用 [docker kill](https://docs.docker.com/engine/reference/commandline/kill/) 命令停止容器。在此命令中，將 `3766c4ab331c` 替換為上一步驟中的容器 ID。

   ```
   docker kill 3766c4ab331c
   ```

### 部署映像
<a name="java-alt-deploy"></a>

**若要將映像上傳至 Amazon ECR 並建立 Lambda 函數**

1. 使用 [get-login-password](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ecr/get-login-password.html) 命令，向 Amazon ECR 登錄檔驗證 Docker CLI。
   + 將 `--region`值設定為您要 AWS 區域 在其中建立 Amazon ECR 儲存庫的 。
   + `111122223333` 以您的 AWS 帳戶 ID 取代 。

   ```
   aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 111122223333.dkr.ecr.us-east-1.amazonaws.com
   ```

1. 使用 [create-repository](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ecr/create-repository.html) 命令在 Amazon ECR 中建立儲存庫。

   ```
   aws ecr create-repository --repository-name hello-world --region us-east-1 --image-scanning-configuration scanOnPush=true --image-tag-mutability MUTABLE
   ```
**注意**  
Amazon ECR 儲存庫必須與 Lambda 函數位於相同的 AWS 區域 中。

   如果成功，您將會看到以下回應：

   ```
   {
       "repository": {
           "repositoryArn": "arn:aws:ecr:us-east-1:111122223333:repository/hello-world",
           "registryId": "111122223333",
           "repositoryName": "hello-world",
           "repositoryUri": "111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world",
           "createdAt": "2023-03-09T10:39:01+00:00",
           "imageTagMutability": "MUTABLE",
           "imageScanningConfiguration": {
               "scanOnPush": true
           },
           "encryptionConfiguration": {
               "encryptionType": "AES256"
           }
       }
   }
   ```

1. 從上一步驟的輸出中複製 `repositoryUri`。

1. 執行 [docker tag](https://docs.docker.com/engine/reference/commandline/tag/) 命令，將 Amazon ECR 儲存庫中的本機映像標記為最新版本。在此命令中：
   + `docker-image:test` 為 Docker 映像檔的名稱和[標籤](https://docs.docker.com/engine/reference/commandline/build/#tag)。這是您在 `docker build` 命令中指定的映像名稱和標籤。
   + 將 `<ECRrepositoryUri>` 替換為複製的 `repositoryUri`。確保在 URI 的末尾包含 `:latest`。

   ```
   docker tag docker-image:test <ECRrepositoryUri>:latest
   ```

   範例：

   ```
   docker tag docker-image:test 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
   ```

1. 執行 [docker push](https://docs.docker.com/engine/reference/commandline/push/) 命令，將本機映像部署至 Amazon ECR 儲存庫。確保在儲存庫 URI 的末尾包含 `:latest`。

   ```
   docker push 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
   ```

1. [建立函數的執行角色](lambda-intro-execution-role.md#permissions-executionrole-api) (若您還沒有的話)。在下一個步驟中您需要角色的 Amazon Resource Name (ARN)。

1. 建立 Lambda 函數。對於 `ImageUri`，從之前的設定中指定儲存庫 URI。確保在 URI 的末尾包含 `:latest`。

   ```
   aws lambda create-function \
     --function-name hello-world \
     --package-type Image \
     --code ImageUri=111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest \
     --role arn:aws:iam::111122223333:role/lambda-ex
   ```
**注意**  
只要映像與 Lambda 函數位於相同的區域，您就可以使用不同 AWS 帳戶中的映像來建立函數。如需詳細資訊，請參閱[Amazon ECR 跨帳戶許可](images-create.md#configuration-images-xaccount-permissions)。

1. 調用函數。

   ```
   aws lambda invoke --function-name hello-world response.json
   ```

   您應該看到如下回應：

   ```
   {
     "ExecutedVersion": "$LATEST", 
     "StatusCode": 200
   }
   ```

1. 若要查看函數的輸出，請檢查 `response.json` 檔案。

若要更新函數程式碼，您必須再次建置映像、將新映像上傳到 Amazon ECR 存放庫，然後使用 [update-function-code](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-code.html) 命令將映像部署到 Lambda 函數。

Lambda 會將映像標籤解析為特定映像摘要。這表示如果您將用來部署函數的映像標籤指向 Amazon ECR 中的新映像，Lambda 不會自動更新函數以使用新映像。

若要將新映像部署至相同的 Lambda 函數，必須使用 [update-function-code](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-code.html) 命令，即使 Amazon ECR 中的映像標籤保持不變亦如此。在以下範例中，`--publish` 選項會使用更新的容器映像來建立新的函數版本。

```
aws lambda update-function-code \
  --function-name hello-world \
  --image-uri 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest \
  --publish
```

# 使用 Java Lambda 函數的層
<a name="java-layers"></a>

使用 [Lambda 層](chapter-layers.md)封裝要在多個函式之間重複使用的程式碼與相依項。層通常具備程式庫相依性、[自訂執行期](runtimes-custom.md)或組態檔案。建立層包含三個一般步驟：

1. 封裝層內容。這表示建立 .zip 封存檔，其中包含您要在函數中使用的相依項。

1. 在 Lambda 中建立層。

1. 將層新增至函數中。

**Topics**
+ [封裝層內容](#java-layers-package)
+ [在 Lambda 中建立層](#publishing-layer)
+ [將層新增至函式](#java-layer-adding)

## 封裝層內容
<a name="java-layers-package"></a>

若要建立層，請將套件封裝成符合以下要求的 .zip 壓縮檔：
+ 確保 Maven 或 Gradle 引用的 Java 版本，與您打算部署的函式所使用的 Java 版本一致。例如，對於 Java 25 函數，`mvn -v`命令應在輸出中列出 Java 25。
+ 相依項必須儲存在 .zip 檔案根目錄下的 `java/lib` 目錄中。如需詳細資訊，請參閱[每個 Lambda 執行時間的層路徑](packaging-layers.md#packaging-layers-paths)。
+ 層中的套件必須與 Linux 相容。Lambda 函式會在 Amazon Linux 上執行。

您可以建立包含第三方 Java 程式庫的層，或您自訂的 Java 模組與套件的層。以下流程使用 Maven 實作。您也可以選用 Gradle 來封裝層內容。

**使用 Maven 相依項建立層**

1. 建立一個包含 `pom.xml` 檔案的 Apache Maven 專案，並在該檔案中定義相依項目。

   下列範例包含用於 JSON 處理的 [Jackson Databind](https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind)。`<build>` 區段透過 [maven-dependency-plugin](https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-dependency-plugin) 為每個相依項建立獨立的 JAR 檔案，而非將其封裝成單一 uber-jar。若需建立 uber-jar，請改用 [maven-shade-plugin](https://maven.apache.org/plugins/maven-shade-plugin/)。  
**Example pom.xml**  

   ```
   <dependencies>
       <dependency>
           <groupId>com.fasterxml.jackson.core</groupId>
           <artifactId>jackson-databind</artifactId>
           <version>2.17.0</version>
       </dependency>
   </dependencies>
   
   <build>
       <plugins>
           <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-compiler-plugin</artifactId>
               <version>3.13.0</version>
               <configuration>
                   <source>21</source>
                   <target>21</target>
                   <release>21</release>
               </configuration>
           </plugin>
           
           <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-dependency-plugin</artifactId>
               <version>3.6.1</version>
               <executions>
                   <execution>
                       <id>copy-dependencies</id>
                       <phase>package</phase>
                       <goals>
                           <goal>copy-dependencies</goal>
                       </goals>
                       <configuration>
                           <outputDirectory>${project.build.directory}/lib</outputDirectory>
                       </configuration>
                   </execution>
               </executions>
           </plugin>
       </plugins>
   </build>
   ```

1. 建置專案。此命令會在 `target/lib/` 目錄中建立所有相依項 JAR 檔案。

   ```
   mvn clean package
   ```

1. 建立層所需的目錄結構：

   ```
   mkdir -p java/lib
   ```

1. 將相依項 JAR 檔案複製至 `java/lib` 目錄：

   ```
   cp target/lib/*.jar java/lib/
   ```

1. 壓縮層內容：

------
#### [ Linux/macOS ]

   ```
   zip -r layer.zip java/
   ```

------
#### [ PowerShell ]

   ```
   Compress-Archive -Path .\java -DestinationPath .\layer.zip
   ```

------

   .zip 檔案的目錄結構應如下所示：

   ```
   java/              
   └── lib/
       ├── jackson-databind-2.17.0.jar
       ├── jackson-core-2.17.0.jar
       └── jackson-annotations-2.17.0.jar
   ```
**注意**  
請確保 .zip 檔案在根層級包含 `java` 目錄，且該目錄內含 `lib` 子目錄。此結構可確保 Lambda 能順利找到並匯入程式庫。每個相依項都會作為獨立的 JAR 檔案保留，而非封裝成單一 uber-jar。

## 在 Lambda 中建立層
<a name="publishing-layer"></a>

您可以使用 AWS CLI 或 Lambda 主控台發佈 layer。

------
#### [ AWS CLI ]

執行 [publish-layer-version](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/publish-layer-version.html) AWS CLI 命令來建立 Lambda layer：

```
aws lambda publish-layer-version --layer-name my-layer --zip-file fileb://layer.zip --compatible-runtimes java25
```

[相容的執行時期](https://docs.aws.amazon.com/lambda/latest/api/API_PublishLayerVersion.html#lambda-PublishLayerVersion-request-CompatibleRuntimes)參數為選用參數。指定此參數後，Lambda 會據此在 Lambda 主控台中篩選層。

------
#### [ Console ]

**建立圖層 (主控台)**

1. 開啟 Lambda 主控台中的 [層頁面](https://console.aws.amazon.com/lambda/home#/layers)。

1. 選擇 **建立圖層**。

1. 選擇**上傳 .zip 檔案**，然後上傳先前建立的 .zip 壓縮檔。

1. (選用) 在**相容的執行時期**欄位中，選擇與用於建置層的 Java 版本相對應的 Java 執行時期。

1. 選擇**建立**。

------

## 將層新增至函式
<a name="java-layer-adding"></a>

------
#### [ AWS CLI ]

若要將 layer 連接至函數，請執行 [update-function-configuration](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-configuration.html) AWS CLI 命令。對於 `--layers` 參數，請使用層 ARN。ARN 必須指定版本 (例如 `arn:aws:lambda:us-east-1:123456789012:layer:my-layer:1`)。如需詳細資訊，請參閱[層和層的版本](chapter-layers.md#lambda-layer-versions)。

```
aws lambda update-function-configuration --function-name my-function --cli-binary-format raw-in-base64-out --layers "arn:aws:lambda:us-east-1:123456789012:layer:my-layer:1"
```

如果您使用的是第 2 AWS CLI 版，則需要 **cli-binary-format**選項。若要讓此成為預設的設定，請執行 `aws configure set cli-binary-format raw-in-base64-out`。若要取得更多資訊，請參閱*《AWS Command Line Interface 使用者指南第 2 版》*中 [AWS CLI 支援的全域命令列選項](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)。

------
#### [ Console ]

**將層新增至函式**

1. 開啟 Lambda 主控台中的[函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇函式。

1. 向下捲動至**層**區段，然後選擇**新增層**。

1. 在**選擇層**欄位中，選取**自訂層**，然後選擇要使用的層。
**注意**  
如果未在建立層時新增[相容的執行時期](https://docs.aws.amazon.com/lambda/latest/api/API_PublishLayerVersion.html#lambda-PublishLayerVersion-request-CompatibleRuntimes)，此處不會列出層。您可以改為指定層 ARN。

1. 選擇**新增**。

------

# 自訂 Lambda Java 函數的序列化
<a name="java-custom-serialization"></a>

Lambda [Java 受管執行時期](lambda-java.md#java-runtimes)支援 JSON 事件的自訂序列化。自訂序列化可以簡化程式碼，並可能提高效能。

**Topics**
+ [何時使用自訂序列化](#custom-serialization-use-cases)
+ [實作自訂序列化](#implement-custom-serialization)
+ [測試自訂序列化](#test-custom-serialization)

## 何時使用自訂序列化
<a name="custom-serialization-use-cases"></a>

調用 Lambda 函數時，輸入事件資料需要還原序列化為 Java 物件，函數的輸出需要序列化回可作為函數回應傳回的格式。Lambda Java 受管執行時期提供預設的序列化和還原序列化功能，非常適合處理來自 Amazon API Gateway、Amazon Simple Queue Service (Amazon SQS) 等各種 AWS 服務的事件承載。若要在函數中使用這些服務整合事件，請將 [aws-java-lambda-events](https://mvnrepository.com/artifact/com.amazonaws/aws-lambda-java-events) 相依項新增至您的專案。此 AWS 程式庫包含代表這些服務整合事件的 Java 物件。

您也可以使用自己的物件來代表傳遞至 Lambda 函數的事件 JSON。受管執行時期會嘗試以預設行為將 JSON 序列化至物件的新執行個體。如果預設序列化程式沒有您的使用案例所需的行為，則請使用自訂序列化。

例如，假設您的函數處理程式需要 `Vehicle` 類別作為輸入，且其結構如下：

```
public class Vehicle {
    private String vehicleType;
    private long vehicleId;
}
```

不過，JSON 事件承載如下所示：

```
{
    "vehicle-type": "car",
    "vehicleID": 123
}
```

在這種情況下，受管執行時期的預設序列化期望 JSON 屬性名稱與駝峰式 Java 類別屬性名稱 (`vehicleType`、`vehicleId`) 相符。由於 JSON 事件中的屬性名稱不是駝峰式 (`vehicle-type`、`vehicleID`)，您必須使用自訂序列化。

## 實作自訂序列化
<a name="implement-custom-serialization"></a>

使用[服務提供者介面](https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html)載入您選擇的序列化程式，而不是受管執行時期的預設序列化邏輯。您可以使用標準 `RequestHandler` 介面，將 JSON 事件承載直接序列化至 Java 物件。

**若要在 Lambda Java 函數中使用自訂序列化**

1. 新增 [aws-lambda-java-core](https://mvnrepository.com/artifact/com.amazonaws/aws-lambda-java-core) 程式庫做為相依項。此程式庫包含 [CustomPojoSerializer](https://github.com/aws/aws-lambda-java-libs/blob/main/aws-lambda-java-core/src/main/java/com/amazonaws/services/lambda/runtime/CustomPojoSerializer.java) 介面，以及在 Lambda 中使用 Java 的其他介面定義。

1. 在專案的 `src/main/resources/META-INF/services/` 目錄中建立名為 `com.amazonaws.services.lambda.runtime.CustomPojoSerializer` 的檔案。

1. 在此檔案中，指定自訂序列化工具實作的完全合格名稱，其必須實作 `CustomPojoSerializer` 介面。範例：

   ```
   com.mycompany.vehicles.CustomLambdaSerialzer
   ```

1. 實作 `CustomPojoSerializer` 介面以提供您的自訂序列化邏輯。

1. 在 Lambda 函數中使用標準 `RequestHandler` 介面。受管執行時期將使用自訂序列化程式。

如需如何使用常用程式庫 (例如 fastJson、Gson、Moshi 和 jackson-jr) 實作自訂序列化的更多範例，請參閱 AWS GitHub 儲存庫中的 [custom-serialization](https://github.com/aws/aws-lambda-java-libs/tree/main/samples/custom-serialization) 範例。

## 測試自訂序列化
<a name="test-custom-serialization"></a>

測試您的函數以確定序列化和還原序列化邏輯如預期般運作。您可以使用 AWS Serverless Application Model 命令列介面 (AWS SAM CLI) 模擬 Lambda 承載的調用。這可協助您在引進自訂序列化程式時，快速測試並重複執行函數。

1. 使用您想要用來調用函數的 JSON 事件承載建立一個檔案，然後呼叫 AWS SAM CLI。

1. 執行 [sam local invoke](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-local-invoke.html ) 命令以在本機調用您的函數。範例：

   ```
   sam local invoke -e src/test/resources/event.json
   ```

如需詳細資訊，請參閱 [Locally invoke Lambda functions with AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-using-invoke.html)。

# 自訂 Lambda 函數的 Java 執行時期啟動行為
<a name="java-customization"></a>

此頁面說明 中 Java 函數的特定設定 AWS Lambda。您可以使用這些設定來自訂 Java 執行期啟動行為。這可以減少整體函數延遲並提高整體函數效能，而無需修改任何程式碼。

**Topics**
+ [了解 `JAVA_TOOL_OPTIONS` 環境變數](#java-tool-options)
+ [Log4Shell 的 Log4j 修補程式 Log4Shell](#log4shell-patch)
+ [Ahead-of-Time(AOT) 和 CDS 快取](#aot-cds-caches)

## 了解 `JAVA_TOOL_OPTIONS` 環境變數
<a name="java-tool-options"></a>

在 Java 中，Lambda 支援 `JAVA_TOOL_OPTIONS` 環境變數，以在 Lambda 中設定其他命令列變數。您可以透過各種方式使用此環境變數，例如自訂分層編譯設定。下一個範例將示範如何針對此使用案例使用 `JAVA_TOOL_OPTIONS` 環境變數。

### 範例：自訂分層編譯設定
<a name="tiered-compilation"></a>

分層編譯是 Java 虛擬機器 (JVM) 的功能。您可以使用特定的分層編譯設定來充分利用 JVM 的即時 (JIT) 編譯器。通常，C1 編譯器針對快速啟動時間進行了最佳化。C2 編譯器針對最佳整體效能進行了最佳化，但也使用更多記憶體，並且需要更長的時間來達成目標。有 5 個不同等級的分層編譯。在層級 0，JVM 會解譯 Java 位元組程式碼。在層級 4，JVM 會使用 C2 編譯器來分析應用程式啟動期間收集的分析資料。隨著時間的推移，它會監控程式碼使用情況以識別最佳化。

自訂分層編譯層級可協助您調整 Java 函數效能。對於快速執行的小型函數，將分層編譯設定為層級 1 有助於透過讓 JVM 使用 C1 編譯器來改善冷啟動效能。此設定可快速產生最佳化的原生程式碼，但不會產生任何分析資料，也不會使用 C2 編譯器。對於運算密集的較大函數，將分層編譯設定為第 4 級，可最大限度地提高整體效能，而無需支付佈建每個 Lambda 執行環境後第一次調用期間的額外記憶體消耗和額外最佳化工作。

對於 Java 11 執行期及以下版本，Lambda 會使用預設 JVM 分層編譯設定。對於 Java 17 和 Java 21，Lambda 預設會將 JVM 設定為停止層級 1 的分層編譯。從 Java 25 開始，Lambda 預設仍會停止層級 1 的分層編譯，除非在使用 SnapStart 或佈建並行時，在這種情況下會使用預設 JVM 設定。這可改善 SnapStart 和佈建並行的效能，而不會產生冷啟動懲罰，因為分層編譯在這些情況下是在調用路徑之外執行。若要最大化此優點，您可以在 SnapStart 快照之前或預先佈建佈建並行執行環境時，使用 priming - 在函數初始化期間執行程式碼路徑來觸發 JIT。如需詳細資訊，請參閱部落格文章[，使用進階入門策略搭配 SnapStart 最佳化 AWS Lambda 的冷啟動效能](https://aws.amazon.com/blogs/compute/optimizing-cold-start-performance-of-aws-lambda-using-advanced-priming-strategies-with-snapstart/)。

**自訂分層編譯設定 (主控台)**

1. 開啟 Lambda 主控台中的[函數](https://console.aws.amazon.com/lambda/home#/functions)頁面。

1. 選擇您要自訂分層編譯的 Java 函數。

1. 選擇**組態**索引標籤，然後選擇左側選單中的**環境變數**。

1. 選擇**編輯**。

1. 選擇 **Add environment variable** (新增環境變數)。

1.  針對索引鍵，輸入 `JAVA_TOOL_OPTIONS`。針對值，輸入 `-XX:+TieredCompilation -XX:TieredStopAtLevel=1`。  
![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/java-tool-options-tiered-compilation.png)

1. 選擇**儲存**。

**注意**  
您也可以使用 Lambda SnapStart 來解決冷啟動問題。SnapStart 會使用執行環境的快取快照來顯著改善啟動效能。如需有關 SnapStart 功能、限制和支援區域的詳細資訊，請參閱[使用 Lambda SnapStart 改善啟動效能](snapstart.md)。

### 範例：使用 JAVA\$1TOOL\$1OPTIONS 自訂 GC 行為
<a name="gc-behavior"></a>

Java 11 執行期使用[串行](https://docs.oracle.com/en/java/javase/18/gctuning/available-collectors.html#GUID-45794DA6-AB96-4856-A96D-FDE5F7DEE498)垃圾回收器 (GC) 進行垃圾回收。依預設，Java 17 執行期也會使用串行垃圾回收器。但是，對於 Java 17，您也可以使用 `JAVA_TOOL_OPTIONS` 環境變數來變更預設垃圾回收器。可以在並行垃圾回收器和 [Shenandoah](https://wiki.openjdk.org/display/shenandoah/Main) 垃圾回收器之間進行選擇。

例如，如果工作負載使用更多記憶體和多個 CPU，則請考慮使用並行垃圾回收器以獲得更好的效能。可以透過將下列內容附加到 `JAVA_TOOL_OPTIONS` 環境變數的值來執行此操作：

```
-XX:+UseParallelGC
```

如果您的工作負載有許多短期物件，您可以透過啟用 Java 25 中引入的 Shenandoah 垃圾收集器的世代模式，從較低的記憶體耗用中獲益。若要執行此作業，請將下列項目附加至`JAVA_TOOL_OPTIONS`環境變數的值：

```
-XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational
```

## Log4Shell 的 Log4j 修補程式 Log4Shell
<a name="log4shell-patch"></a>

Java 8、11、17 和 21 的 Lambda 執行時間包含修補程式，可減輕 Log4Shell 漏洞 (CVE-2021-44228)，Log4j熱門的 Java 記錄架構。此修補程式會產生冷啟動效能額外負荷。如果您使用的是修補程式版本的 Log4j (2.17.0 版或更新版本），您可以停用此修補程式來改善冷啟動效能。若要停用修補程式，請將`AWS_LAMBDA_DISABLE_CVE_2021_44228_PROTECTION`環境變數設定為 `true`。

從 Java 25 開始，Lambda 執行時間不再包含 Log4Shell 修補程式。您必須驗證您使用的是 Log4j 2.17.0 版或更新版本。

## Ahead-of-Time(AOT) 和 CDS 快取
<a name="aot-cds-caches"></a>

從 Java 25 開始，Lambda 執行時間包含 Java 執行時間界面用戶端 (RIC) Ahead-of-Time (AOT) 快取，這是一種執行時間元件，可主動輪詢來自 Lambda 執行時間 API 的事件。這可改善冷啟動效能。

AOT 快取專屬於 JVM 組建。當 Lambda 更新受管執行期時，也會更新 RIC 的 AOT 快取。不過，如果您部署自己的 AOT 快取，這些快取可能會失效，或在執行時間更新後導致意外行為。因此，強烈建議在使用受管執行期時不要使用 AOT 快取。若要使用 AOT 快取，您應該使用容器映像部署函數。

AOT 快取無法與類別資料共用 (CDS) 快取搭配使用。如果您在 Lambda 函數中部署 CDS 快取，則 Lambda 會停用 AOT 快取。

# 使用 Lambda 內容物件擷取 Java 函數資訊
<a name="java-context"></a>

當 Lambda 執行您的函數時，它會將內容物件傳遞至[處理常式](java-handler.md)。此物件提供的方法和各項屬性提供了有關調用、函式以及執行環境的資訊。

**內容方法**
+ `getRemainingTimeInMillis()` - 傳回執行逾時前剩餘的毫秒數。
+ `getFunctionName()` – 傳回 Lambda 函數的名稱。
+ `getFunctionVersion()` - 傳回函數的[版本](configuration-versions.md)。
+ `getInvokedFunctionArn()` - 傳回用於叫用此函數的 Amazon Resource Name (ARN)。指出叫用者是否指定版本號或別名。
+ `getMemoryLimitInMB()` - 傳回分配給函數的記憶體數量。
+ `getAwsRequestId()` - 傳回叫用請求的識別符。
+ `getLogGroupName()` - 傳回函數的日誌群組。
+ `getLogStreamName()` - 傳回函數執行個體的記錄串流。
+ `getIdentity()` - (行動應用程式) 傳回已授權請求的 Amazon Cognito 身分的相關資訊。
+ `getClientContext()` - (行動應用程式) 傳回用戶端應用程式提供給 Lambda 的用戶端內容。
+ `getLogger()` - 傳回函數的 [Logger 物件](java-logging.md)。

下面的例子顯示使用內容物件存取 Lambda 記錄器的函數。

**Example [Handler.java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-basic/src/main/java/example/Handler.java)**  

```
package example;

import [com.amazonaws.services.lambda.runtime.Context](https://github.com/aws/aws-lambda-java-libs/blob/master/aws-lambda-java-core/src/main/java/com/amazonaws/services/lambda/runtime/Context.java);
import [com.amazonaws.services.lambda.runtime.LambdaLogger](https://github.com/aws/aws-lambda-java-libs/blob/master/aws-lambda-java-core/src/main/java/com/amazonaws/services/lambda/runtime/LambdaLogger.java);
import [com.amazonaws.services.lambda.runtime.RequestHandler](https://github.com/aws/aws-lambda-java-libs/blob/master/aws-lambda-java-core/src/main/java/com/amazonaws/services/lambda/runtime/RequestHandler.java);

import java.util.Map;

// Handler value: example.Handler
public class Handler implements RequestHandler<Map<String,String>, Void>{

  @Override
  public Void handleRequest(Map<String,String> event, Context context)
  {
    LambdaLogger logger = context.getLogger();
    logger.log("EVENT TYPE: " + event.getClass());
    return null;
  }
}
```

函數會先記錄傳入事件的類別類型，再傳回 `null`。

**Example 記錄輸出**  

```
EVENT TYPE: class java.util.LinkedHashMap
```

內容物件的介面可在 [aws-lambda-java-core](https://github.com/aws/aws-lambda-java-libs/tree/master/aws-lambda-java-core) 程式庫中使用。您可以實作此介面來建立測試的內容類別。下面的例子顯示針對大多數屬性和進行中測試記錄器傳回虛擬值的內容類別。

**Example [src/test/java/example/TestContext.java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-basic/src/test/java/example/TestContext.java)**  

```
package example;

import [com.amazonaws.services.lambda.runtime.Context](https://github.com/aws/aws-lambda-java-libs/blob/master/aws-lambda-java-core/src/main/java/com/amazonaws/services/lambda/runtime/Context.java);
import [com.amazonaws.services.lambda.runtime.CognitoIdentity](https://github.com/aws/aws-lambda-java-libs/blob/master/aws-lambda-java-core/src/main/java/com/amazonaws/services/lambda/runtime/CognitoIdentity.java);
import [com.amazonaws.services.lambda.runtime.ClientContext](https://github.com/aws/aws-lambda-java-libs/blob/master/aws-lambda-java-core/src/main/java/com/amazonaws/services/lambda/runtime/ClientContext.java);
import [com.amazonaws.services.lambda.runtime.LambdaLogger](https://github.com/aws/aws-lambda-java-libs/blob/master/aws-lambda-java-core/src/main/java/com/amazonaws/services/lambda/runtime/LambdaLogger.java);

public class TestContext implements Context{

  public TestContext() {}
  public String getAwsRequestId(){
    return new String("495b12a8-xmpl-4eca-8168-160484189f99");
  }
  public String getLogGroupName(){
    return new String("/aws/lambda/my-function");
  }
  public String getLogStreamName(){
    return new String("2020/02/26/[$LATEST]704f8dxmpla04097b9134246b8438f1a");
  }
  public String getFunctionName(){
    return new String("my-function");
  }
  public String getFunctionVersion(){
    return new String("$LATEST");
  }
  public String getInvokedFunctionArn(){
    return new String("arn:aws:lambda:us-east-2:123456789012:function:my-function");
  }
  public CognitoIdentity getIdentity(){
    return null;
  }
  public ClientContext getClientContext(){
    return null;
  }
  public int getRemainingTimeInMillis(){
    return 300000;
  }
  public int getMemoryLimitInMB(){
    return 512;
  }
  public LambdaLogger getLogger(){
    return new TestLogger();
  }

}
```

如需記錄日誌的詳細資訊，請參閱 [記錄和監控 Java Lambda 函數](java-logging.md)。

## 範例應用程式中的內容
<a name="java-context-samples"></a>

本指南的 GitHub 儲存庫包含示範內容物件使用方式的範例應用程式。每個範例應用程式都包含可輕鬆部署和清理的指令碼、AWS Serverless Application Model (AWS SAM) 範本和支援資源。

**以 Java 編寫的範例 Lambda 應用程式**
+ [example-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/example-java) – Java 函式，示範如何使用 Lambda 處理訂單。此函式示範如何定義並反序列化自訂輸入事件物件、使用 AWS SDK 以及輸出日誌。
+ [java-basic](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-basic) - 具有單元測試和變數日誌組態的最小 Java 函數集合。
+ [java-events](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-events) - Java 函數集合，其中包含如何處理來自各種服務 (例如 Amazon API Gateway、Amazon SQS 和 Amazon Kinesis) 事件的骨架程式碼。這些函數使用最新版 [aws-lambda-java-events](java-package.md) 程式庫 (3.0.0 及更新版)。這些範例不需要 AWS 開發套件做為相依項目。
+ [s3-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/s3-java) - 一種 Java 函數，它處理來自 Amazon S3 的通知事件，並使用 Java Class Library (JCL) 以從上傳的映像檔案建立縮圖。
+ [layer-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/layer-java) – 此 Java 函式示範如何使用 Lambda 層，將相依項與核心函式程式碼分離封裝。

# 記錄和監控 Java Lambda 函數
<a name="java-logging"></a>

AWS Lambda 會自動監控 Lambda 函數，並將日誌項目傳送至 Amazon CloudWatch。您的 Lambda 函數隨附有 CloudWatch Logs 日誌群組，且函數的每一執行個體各有一個日誌串流。Lambda 執行期環境會將每次調用的詳細資訊和函數程式碼的其他輸出，傳送至日誌串流。如需 CloudWatch Logs 的詳細資訊，請參閱[將 Lambda 函式日誌傳送至 CloudWatch Logs](monitoring-cloudwatchlogs.md)。

若要由您的函數程式碼輸出日誌，可以使用 [java.lang.System](https://docs.oracle.com/javase/8/docs/api/java/lang/System.html) 的方法，或任何能寫入 stdout 或 stderr 的記錄模組。

**Topics**
+ [建立傳回日誌的函數](#java-logging-output)
+ [搭配 Java 使用 Lambda 進階日誌控制項](#java-logging-advanced)
+ [使用 Log4j2 和 SLF4J 實作進階日誌記錄](#java-logging-log4j2)
+ [使用其他記錄工具和程式庫](#java-tools-libraries)
+ [使用 Powertools for AWS Lambda (Java) 和 AWS SAM 進行結構化記錄](#java-logging-sam)
+ [在 Lambda 主控台檢視日誌](#java-logging-console)
+ [在 CloudWatch 主控台中檢視 記錄](#java-logging-cwconsole)
+ [使用 AWS Command Line Interface (AWS CLI) 檢視日誌](#java-logging-cli)
+ [刪除日誌](#java-logging-delete)
+ [日誌記錄程式碼範例](#java-logging-samples)

## 建立傳回日誌的函數
<a name="java-logging-output"></a>

若要由您的函數程式碼輸出日誌，您可以使用 [java.lang.System](https://docs.oracle.com/javase/8/docs/api/java/lang/System.html) 的方法，或任何能寫入 `stdout` 或 `stderr` 的記錄模組。在 [aws-lambda-java-core](java-package.md) 程式庫會提供了一個名為 `LambdaLogger` 的記錄器類別，您可以從內容物件加以存取。記錄器類別支援多行日誌。

下面範例使用由內容物件提供的 `LambdaLogger` 記錄器。

**Example Handler.java**  

```
// Handler value: example.Handler
public class Handler implements RequestHandler<Object, String>{
  Gson gson = new GsonBuilder().setPrettyPrinting().create();
  @Override
  public String handleRequest(Object event, Context context)
  {
    LambdaLogger logger = context.getLogger();
    String response = new String("SUCCESS");
    // log execution details
    logger.log("ENVIRONMENT VARIABLES: " + gson.toJson(System.getenv()));
    logger.log("CONTEXT: " + gson.toJson(context));
    // process event
    logger.log("EVENT: " + gson.toJson(event));
    return response;
  }
}
```

**Example 記錄格式**  

```
START RequestId: 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 Version: $LATEST
ENVIRONMENT VARIABLES: 
{
    "_HANDLER": "example.Handler",
    "AWS_EXECUTION_ENV": "AWS_Lambda_java8",
    "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "512",
    ...
}
CONTEXT: 
{
    "memoryLimit": 512,
    "awsRequestId": "6bc28136-xmpl-4365-b021-0ce6b2e64ab0",
    "functionName": "java-console",
    ...
}
EVENT:
{
  "records": [
    {
      "messageId": "19dd0b57-xmpl-4ac1-bd88-01bbb068cb78",
      "receiptHandle": "MessageReceiptHandle",
      "body": "Hello from SQS!",
       ...
    }
  ]
}
END RequestId: 6bc28136-xmpl-4365-b021-0ce6b2e64ab0
REPORT RequestId: 6bc28136-xmpl-4365-b021-0ce6b2e64ab0	Duration: 198.50 ms	Billed Duration: 724 ms	Memory Size: 512 MB	Max Memory Used: 90 MB	Init Duration: 524.75 ms
```

Java 執行時間會記錄每次調用的 `START`、`END` 和 `REPORT` 行。報告明細行提供下列詳細資訊：

**REPORT 行資料欄位**
+ **RequestId** - 進行調用的唯一請求 ID。
+ **持續時間** - 函數的處理常式方法處理事件所花費的時間量。
+ **計費持續時間** - 調用的計費時間量。
+ **記憶體大小** - 分配給函數的記憶體數量。
+ **使用的記憶體上限** - 函數所使用的記憶體數量。當調用共用執行環境時，Lambda 會報告所有調用使用的記憶體上限。此行為可能會導致報告值高於預期值。
+ **初始化持續時間** - 對於第一個提供的請求，這是執行期載入函數並在處理常式方法之外執行程式碼所花費的時間量。
+ **XRAY TraceId** - 對於追蹤的請求，這是 [AWS X-Ray 追蹤 ID](services-xray.md)。
+ **SegmentId** - 對於追蹤的請求，這是 X-Ray 區段 ID。
+ **已取樣** - 對於追蹤的請求，這是取樣結果。

## 搭配 Java 使用 Lambda 進階日誌控制項
<a name="java-logging-advanced"></a>

為了讓您更妥善地控制擷取、處理和使用函數日誌的方式，您可以針對支援的 Java 執行期設定下列記錄選項：
+ **日誌格式** - 在純文字和結構化 JSON 格式之間為您的日誌進行選擇
+ **日誌層級** - 對於 JSON 格式的日誌，請選擇 Lambda 傳送到 CloudWatch 的日誌之詳細等級，例如 ERROR、DEBUG 或 INFO
+ **日誌群組** - 選擇您的函數將日誌傳送到的 CloudWatch 日誌群組

如需這些日誌選項的詳細資訊，以及如何設定函數以使用這些選項的說明，請參閱 [設定 Lambda 函數的進階日誌記錄控制項](monitoring-logs.md#monitoring-cloudwatchlogs-advanced)。

若要使用日誌格式和日誌層級選項與 Java Lambda 函數搭配使用，請參閱以下各章節中的指引。

### 搭配 Java 使用結構化 JSON 日誌格式
<a name="java-logging-advanced-JSON"></a>

如果您為函數的日誌格式選取 JSON，Lambda 會以結構化 JSON 形式使用 `LambdaLogger` 類別傳送日誌輸出。每個 JSON 日誌物件都包含至少四個鍵值對，其中包含下列索引鍵：
+ `"timestamp"` - 產生日誌訊息的時間
+ `"level"` - 指派給訊息的日誌層級
+ `"message"` - 日誌訊息的內容
+ `"AWSrequestId"` - 進行調用的唯一請求 ID。

視您使用的記錄方法而定，以 JSON 格式擷取之函數的日誌輸出也可以包含其他鍵值對。

若要將您使用 `LambdaLogger` 記錄器建立的日誌指派一個層級，你需要在你的日誌命令提供一個 `LogLevel` 引數，如以下的例子。

**Example Java 日誌程式碼**  

```
LambdaLogger logger = context.getLogger();
logger.log("This is a debug log", LogLevel.DEBUG);
```

此範例程式碼所輸出的日誌檔會在 CloudWatch Logs 中擷取，如下所示：

**Example JSON 日誌記錄**  

```
{
    "timestamp":"2023-11-01T00:21:51.358Z",
    "level":"DEBUG",
    "message":"This is a debug log",
    "AWSrequestId":"93f25699-2cbf-4976-8f94-336a0aa98c6f"
}
```

如果您沒有為日誌輸出指派層級，Lambda 會自動為其指派層級 INFO。

如果您的程式碼已經使用另一個記錄程式庫來生成 JSON 結構化日誌，則不需要進行任何更改。Lambda 不會對任何已經進行 JSON 編碼的記錄進行雙重編碼。即使您將函數設定為使用 JSON 日誌格式，您的記錄輸出也會以您定義的 JSON 結構顯示於 CloudWatch 中。

### 搭配 Java 使用日誌層級篩選
<a name="java-logging-advanced-levels"></a>

若要 AWS Lambda 讓 根據應用程式日誌層級篩選您的應用程式日誌，您的函數必須使用 JSON 格式的日誌。您可以透過兩種方式達成此操作：
+ 使用標準 `LambdaLogger` 建立日誌輸出，並將函數設定為使用 JSON 日誌格式。然後，Lambda 會使用 [搭配 Java 使用結構化 JSON 日誌格式](#java-logging-advanced-JSON) 中所述 JSON 物件中的「層級」索引鍵值組篩選您的日誌輸出。若要瞭解如何設定函數的日誌格式，請參閱 [設定 Lambda 函數的進階日誌記錄控制項](monitoring-logs.md#monitoring-cloudwatchlogs-advanced)。
+ 使用其他日誌程式庫或方法，在您的程式碼中建立 JSON 結構化日誌，其中包含定義日誌輸出層級的「層級」索引鍵值組。您可以使用可將 JSON 日誌寫入 `stdout` 或 `stderr` 的任何記錄程式庫。例如，您可以使用 Powertools for AWS Lambda 或 Log4j2 套件，從您的程式碼產生 JSON 結構化日誌輸出。如需進一步了解，請參閱 [使用 Powertools for AWS Lambda (Java) 和 AWS SAM 進行結構化記錄](#java-logging-sam) 和 [使用 Log4j2 和 SLF4J 實作進階日誌記錄](#java-logging-log4j2)。

將函數設定為使用日誌層級篩選時，您必須從下列選項中選取要 Lambda 傳送至 CloudWatch Logs 的日誌層級：


| 日誌層級 | 標準用量 | 
| --- | --- | 
| TRACE (大多數詳細資訊) | 用於追蹤程式碼執行路徑的最精細資訊 | 
| DEBUG | 系統偵錯的詳細資訊 | 
| INFO | 記錄函數正常操作的訊息 | 
| WARN | 有關可能導致未解決意外行為的潛在錯誤的消息 | 
| ERROR | 有關阻止程式碼按預期執行的問題的訊息 | 
| FATAL (最少詳細資訊) | 有關導致應用程式停止運作的嚴重錯誤訊息 | 

若要讓 Lambda 篩選函數的日誌，您還必須在 JSON 日誌輸出中包含 `"timestamp"` 索引鍵值組。必須以有效的 [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) 時間戳記格式指定時間。如果您沒有提供有效的時間戳記，Lambda 會為日誌指派層級 INFO，並為您新增時間戳記。

Lambda 會在選取的層級 (含) 和更低層級傳送日誌給 CloudWatch。例如，如果您設定 WARN 的日誌層級，Lambda 會傳送相對應於 WARN、ERROR 和 FATAL 層級的日誌檔。

## 使用 Log4j2 和 SLF4J 實作進階日誌記錄
<a name="java-logging-log4j2"></a>

**注意**  
 AWS Lambda 在其受管執行時間或基礎容器映像中不包含 Log4j2。因此，這些問題不受 CVE-2021-44228、CVE-2021-45046 以及 CVE-2021-45105 中描述的問題的影響。  
 對於客戶函數包含受影響的 Log4j2 版本的情況，我們已將變更套用至 Lambda Java [受管執行時間](lambda-runtimes.md)和[基礎容器映像](java-image.md)，這有助於緩解 CVE-2021-44228、CVE-2021-45046 和 CVE-2021-45105 中的問題。由於此變更，使用 Log4J2 的客戶可能會看到一個額外的日誌條目，類似於「`Transforming org/apache/logging/log4j/core/lookup/JndiLookup (java.net.URLClassLoader@...)`」。在 Log4J2 輸出中參考 jndi 映射器的任何日誌字串都將替換為「`Patched JndiLookup::lookup()`」。  
 除此變更之外，我們強烈建議其函數包含 Log4j2 的所有客戶將 Log4j2 更新至最新版本。具體而言，在函數中使用 aws-lambda-java-log4j2 程式庫的客戶應更新至 1.5.0 版 (或更高版本)，並重新部署其函數。此版本將基礎 Log4j2 公用程式相依性更新為 2.17.0 版 (或更高版本)。更新後的 aws-lambda-java-log4j2 二進位文件可在 [Maven 儲存庫](https://repo1.maven.org/maven2/com/amazonaws/aws-lambda-java-log4j2/)中找到，而其原始碼可在 [GitHub](https://github.com/aws/aws-lambda-java-libs/tree/master/aws-lambda-java-log4j2) 中找到。  
 最後，請注意，在**任何**情況下都**不**應使用與 **aws-lambda-java-log4j (v1.0.0 or 1.0.1)** 相關的任何程式庫。這些程式庫與 log4j 的 第 1.x 版本相關，該版本已於 2015 年停止使用。這些程式庫不受支援、未受維護、未經修補，且具有已知的安全性漏洞。

若要自訂日誌輸出、在單元測試期間支援日誌記錄，以及日誌 AWS SDK 呼叫，請使用 Apache Log4j2 搭配 SLF4J。Log4j 是適用於 Java 程式的日誌程式庫，讓您能夠配置日誌級別和使用附加器程式庫。SLF4J 是一個外觀程式庫，可讓您改變使用的程式庫，而無須您的函數程式碼。

若要將請求 ID 新增至函數的日誌中，請使用 [aws-lambda-java-log4j2](java-package.md) 程式庫中的附加器。

**Example [src/main/resources/log4j2.xml](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/s3-java/src/main/resources/log4j2.xml) - 附加器組態**  

```
<Configuration>
  <Appenders>
    <Lambda name="Lambda" format="${env:AWS_LAMBDA_LOG_FORMAT:-TEXT}">
       <LambdaTextFormat>
         <PatternLayout>
             <pattern>%d{yyyy-MM-dd HH:mm:ss} %X{AWSRequestId} %-5p %c{1} - %m%n </pattern>
         </PatternLayout>
       </LambdaTextFormat>
       <LambdaJSONFormat>
         <JsonTemplateLayout eventTemplateUri="classpath:LambdaLayout.json" />
       </LambdaJSONFormat>
     </Lambda>
   </Appenders>
   <Loggers>
     <Root level="${env:AWS_LAMBDA_LOG_LEVEL:-INFO}">
       <AppenderRef ref="Lambda"/>
     </Root>
     <Logger name="software.amazon.awssdk" level="WARN" />
     <Logger name="software.amazon.awssdk.request" level="DEBUG" />
   </Loggers>
 </Configuration>
```

您可以透過在 `<LambdaTextFormat>` 和 `<LambdaJSONFormat>` 標籤下指定佈局來決定如何將 Log4j2 日誌配置為純文本或 JSON 輸出。

在此範例中，每一行前面都會以文字模式加上日期、時間、請求 ID、日誌層級和類別名稱。在 JSON 模式下`<JsonTemplateLayout>`，會與 `aws-lambda-java-log4j2` 程式庫一起隨附的組態搭配使用。

SLF4J 是使用 Java 程式碼進行日誌記錄的外觀程式庫。在您的函數程式碼中，您可以使用 SLF4J 記錄器工廠來擷取帶有日誌層級方法的記錄器，如 `info()` 和 `warn()`。在您的建置組態中，您可將日誌記錄程式庫和 SLF4J 轉接器包含在 classpath 中。透過在建置配置中更改程式庫，您可以在不更改函數代碼的情況下更改記錄器類型。需要 SLF4J 才能從 SDK for Java 中擷取日誌。

在下面範例程式碼中，處理常式類別會使用 SLF4J 來擷取記錄器。

**Example [src/main/java/example/HandlerS3.java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-events/src/main/java/example/HandlerS3.java) – 透過 SLF4J 進行日誌記錄**  

```
package example;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.S3Event;

import static org.apache.logging.log4j.CloseableThreadContext.put;


public class HandlerS3 implements RequestHandler<S3Event, String>{
    private static final Logger logger = LoggerFactory.getLogger(HandlerS3.class);

    @Override
    public String handleRequest(S3Event event, Context context) {
        for(var record : event.getRecords()) {
            try (var loggingCtx = put("awsRegion", record.getAwsRegion())) {
                loggingCtx.put("eventName", record.getEventName());
                loggingCtx.put("bucket", record.getS3().getBucket().getName());
                loggingCtx.put("key", record.getS3().getObject().getKey());

                logger.info("Handling s3 event");
            }
        }

        return "Ok";
    }
}
```

此程式碼產生的日誌輸出如以下所示。

**Example 記錄格式**  

```
{
    "timestamp": "2023-11-15T16:56:00.815Z",
    "level": "INFO",
    "message": "Handling s3 event",
    "logger": "example.HandlerS3",
    "AWSRequestId": "0bced576-3936-4e5a-9dcd-db9477b77f97",
    "awsRegion": "eu-south-1",
    "bucket": "java-logging-test-input-bucket",
    "eventName": "ObjectCreated:Put",
    "key": "test-folder/"
}
```

建置組態會使用 Lambda 附加器和 SLF4J 轉接器的執行期相依性，以及 Log4j2 的實作相依性。

**Example build.gradle - 日誌記錄相依性**  

```
dependencies {
    ...
    'com.amazonaws:aws-lambda-java-log4j2:[1.6.0,)',
    'com.amazonaws:aws-lambda-java-events:[3.11.3,)',
    'org.apache.logging.log4j:log4j-layout-template-json:[2.17.1,)',
    'org.apache.logging.log4j:log4j-slf4j2-impl:[2.19.0,)',
    ...
}
```

當您在本機執行程式碼進行測試時，帶有 Lambda 記錄器的內容物件將無法使用，並且 Lambda 附加器沒有可使用的請求 ID。對於範例測試組態，請參閱下節中的範例應用程式。

## 使用其他記錄工具和程式庫
<a name="java-tools-libraries"></a>

[Powertools for AWS Lambda (Java)](https://docs.aws.amazon.com/powertools/java/) 是一種開發人員工具組，可實作無伺服器最佳實務並提高開發人員速度。[記錄公用程式](https://docs.aws.amazon.com/powertools/java/latest/core/logging/)提供 Lambda 優化記錄器，其中包含有關所有函數之函數內容的其他資訊，輸出結構為 JSON。使用此公用程式執行下列操作：
+ 從 Lambda 內容、冷啟動和 JSON 形式的結構記錄輸出中擷取關鍵欄位
+ 在收到指示時記錄 Lambda 調用事件 (預設為停用)
+ 透過日誌採樣僅列印調用百分比的所有日誌 (預設為停用)
+ 在任何時間點將其他金鑰附加至結構化日誌
+ 使用自訂日誌格式化程式 (自帶格式化程式)，以與組織的日誌記錄 RFC 相容的結構輸出日誌。

## 使用 Powertools for AWS Lambda (Java) 和 AWS SAM 進行結構化記錄
<a name="java-logging-sam"></a>

請依照下列步驟，使用 下載、建置和部署範例 Hello World Java 應用程式，並整合 [Powertools for AWS Lambda (Java)](https://docs.aws.amazon.com/powertools/java/latest/) 模組 AWS SAM。此應用程式實作了基本 API 後端，並使用 Powertools 發送日誌、指標和追蹤。其包含 Amazon API Gateway 端點和 Lambda 函數。當您將 GET 請求傳送至 API Gateway 端點時，Lambda 函數會調用、使用內嵌指標格式將日誌和指標傳送至 CloudWatch，並將追蹤傳送至 AWS X-Ray。該函數會傳回 `hello world` 訊息。

**先決條件**

若要完成本節中的步驟，您必須執行下列各項：
+ Java 11
+ [AWS CLI 第 2 版](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS SAM CLI 1.75 版或更新版本。](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)如果您有較舊版本的 AWS SAM CLI，請參閱[升級 AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/manage-sam-cli-versions.html#manage-sam-cli-versions-upgrade)。

**部署範例 AWS SAM 應用程式**

1. 使用 Hello World Java 範本來初始化應用程式。

   ```
   sam init --app-template hello-world-powertools-java --name sam-app --package-type Zip --runtime java11 --no-tracing
   ```

1. 建置應用程式。

   ```
   cd sam-app && sam build
   ```

1. 部署應用程式。

   ```
   sam deploy --guided
   ```

1. 依照螢幕上的提示操作。若要接受互動體驗中提供的預設選項，請按下 `Enter`。
**注意**  
對於 **HelloWorldFunction may not have authorization defined, Is this okay?**，確保輸入 `y`。

1. 取得已部署應用程式的 URL：

   ```
   aws cloudformation describe-stacks --stack-name sam-app --query 'Stacks[0].Outputs[?OutputKey==`HelloWorldApi`].OutputValue' --output text
   ```

1. 調用 API 端點：

   ```
   curl -X GET <URL_FROM_PREVIOUS_STEP>
   ```

   成功的話，您將會看到以下回應：

   ```
   {"message":"hello world"}
   ```

1. 若要獲取該函數的日誌，請執行 [sam 日誌](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-logs.html)。如需詳細資訊，請參閱《AWS Serverless Application Model 開發人員指南》** 中的 [使用日誌](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html)。

   ```
   sam logs --stack-name sam-app
   ```

   日誌輸出如下：

   ```
   2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:34.095000 INIT_START Runtime Version: java:11.v15    Runtime Version ARN: arn:aws:lambda:eu-central-1::runtime:0a25e3e7a1cc9ce404bc435eeb2ad358d8fa64338e618d0c224fe509403583ca
   2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:34.114000 Picked up JAVA_TOOL_OPTIONS: -XX:+TieredCompilation -XX:TieredStopAtLevel=1
   2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:34.793000 Transforming org/apache/logging/log4j/core/lookup/JndiLookup (lambdainternal.CustomerClassLoader@1a6c5a9e)
   2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:35.252000 START RequestId: 7fcf1548-d2d4-41cd-a9a8-6ae47c51f765 Version: $LATEST
   2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:36.531000 {
     "_aws": {
       "Timestamp": 1675416276051,
       "CloudWatchMetrics": [
         {
           "Namespace": "sam-app-powerools-java",
           "Metrics": [
             {
               "Name": "ColdStart",
               "Unit": "Count"
             }
           ],
           "Dimensions": [
             [
               "Service",
               "FunctionName"
             ]
           ]
         }
       ]
     },
     "function_request_id": "7fcf1548-d2d4-41cd-a9a8-6ae47c51f765",
     "traceId": "Root=1-63dcd2d1-25f90b9d1c753a783547f4dd;Parent=e29684c1be352ce4;Sampled=1",
     "FunctionName": "sam-app-HelloWorldFunction-y9Iu1FLJJBGD",
     "functionVersion": "$LATEST",
     "ColdStart": 1.0,
     "Service": "service_undefined",
     "logStreamId": "2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81",
     "executionEnvironment": "AWS_Lambda_java11"
   }
   2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:36.974000 Feb 03, 2023 9:24:36 AM com.amazonaws.xray.AWSXRayRecorder <init>
   2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:36.993000 Feb 03, 2023 9:24:36 AM com.amazonaws.xray.config.DaemonConfiguration <init>
   2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:36.993000 INFO: Environment variable AWS_XRAY_DAEMON_ADDRESS is set. Emitting to daemon on address XXXX.XXXX.XXXX.XXXX:2000.
   2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:37.331000 09:24:37.294 [main] INFO  helloworld.App - {"version":null,"resource":"/hello","path":"/hello/","httpMethod":"GET","headers":{"Accept":"*/*","CloudFront-Forwarded-Proto":"https","CloudFront-Is-Desktop-Viewer":"true","CloudFront-Is-Mobile-Viewer":"false","CloudFront-Is-SmartTV-Viewer":"false","CloudFront-Is-Tablet-Viewer":"false","CloudFront-Viewer-ASN":"16509","CloudFront-Viewer-Country":"IE","Host":"XXXX.execute-api.eu-central-1.amazonaws.com","User-Agent":"curl/7.86.0","Via":"2.0 f0300a9921a99446a44423d996042050.cloudfront.net (CloudFront)","X-Amz-Cf-Id":"t9W5ByT11HaY33NM8YioKECn_4eMpNsOMPfEVRczD7T1RdhbtiwV1Q==","X-Amzn-Trace-Id":"Root=1-63dcd2d1-25f90b9d1c753a783547f4dd","X-Forwarded-For":"XX.XXX.XXX.XX, XX.XXX.XXX.XX","X-Forwarded-Port":"443","X-Forwarded-Proto":"https"},"multiValueHeaders":{"Accept":["*/*"],"CloudFront-Forwarded-Proto":["https"],"CloudFront-Is-Desktop-Viewer":["true"],"CloudFront-Is-Mobile-Viewer":["false"],"CloudFront-Is-SmartTV-Viewer":["false"],"CloudFront-Is-Tablet-Viewer":["false"],"CloudFront-Viewer-ASN":["16509"],"CloudFront-Viewer-Country":["IE"],"Host":["XXXX.execute-api.eu-central-1.amazonaws.com"],"User-Agent":["curl/7.86.0"],"Via":["2.0 f0300a9921a99446a44423d996042050.cloudfront.net (CloudFront)"],"X-Amz-Cf-Id":["t9W5ByT11HaY33NM8YioKECn_4eMpNsOMPfEVRczD7T1RdhbtiwV1Q=="],"X-Amzn-Trace-Id":["Root=1-63dcd2d1-25f90b9d1c753a783547f4dd"],"X-Forwarded-For":["XXX, XXX"],"X-Forwarded-Port":["443"],"X-Forwarded-Proto":["https"]},"queryStringParameters":null,"multiValueQueryStringParameters":null,"pathParameters":null,"stageVariables":null,"requestContext":{"accountId":"XXX","stage":"Prod","resourceId":"at73a1","requestId":"ba09ecd2-acf3-40f6-89af-fad32df67597","operationName":null,"identity":{"cognitoIdentityPoolId":null,"accountId":null,"cognitoIdentityId":null,"caller":null,"apiKey":null,"principalOrgId":null,"sourceIp":"54.240.197.236","cognitoAuthenticationType":null,"cognitoAuthenticationProvider":null,"userArn":null,"userAgent":"curl/7.86.0","user":null,"accessKey":null},"resourcePath":"/hello","httpMethod":"GET","apiId":"XXX","path":"/Prod/hello/","authorizer":null},"body":null,"isBase64Encoded":false}
   2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:37.351000 09:24:37.351 [main] INFO  helloworld.App - Retrieving https://checkip.amazonaws.com
   2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:39.313000 {
     "function_request_id": "7fcf1548-d2d4-41cd-a9a8-6ae47c51f765",
     "traceId": "Root=1-63dcd2d1-25f90b9d1c753a783547f4dd;Parent=e29684c1be352ce4;Sampled=1",
     "xray_trace_id": "1-63dcd2d1-25f90b9d1c753a783547f4dd",
     "functionVersion": "$LATEST",
     "Service": "service_undefined",
     "logStreamId": "2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81",
     "executionEnvironment": "AWS_Lambda_java11"
   }
   2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:39.371000 END RequestId: 7fcf1548-d2d4-41cd-a9a8-6ae47c51f765
   2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:39.371000 REPORT RequestId: 7fcf1548-d2d4-41cd-a9a8-6ae47c51f765    Duration: 4118.98 ms    Billed Duration: 5275 ms    Memory Size: 512 MB    Max Memory Used: 152 MB    Init Duration: 1155.47 ms    
   XRAY TraceId: 1-63dcd2d1-25f90b9d1c753a783547f4dd    SegmentId: 3a028fee19b895cb    Sampled: true
   ```

1. 這是可透過網際網路存取的公有 API 端點。建議您在測試後刪除端點。

   ```
   sam delete
   ```

### 管理日誌保留
<a name="java-log-retention"></a>

當您刪除函數時，不會自動刪除日誌群組。若要避免無限期地儲存日誌，請刪除日誌群組，或設定保留期間，CloudWatch 會在該時間之後自動刪除日誌。若要設定日誌保留，請將下列項目新增至您的 AWS SAM 範本：

```
Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      # Omitting other properties

  LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub "/aws/lambda/${HelloWorldFunction}"
      RetentionInDays: 7
```

## 在 Lambda 主控台檢視日誌
<a name="java-logging-console"></a>

您可以在調用 Lambda 函數之後，使用 Lambda 主控台來檢視日誌輸出。

如果可以從內嵌**程式碼**編輯器測試您的程式碼，您會在**執行結果**中找到日誌。使用主控台測試功能以調用函數時，您會在**詳細資訊**區段找到**日誌輸出**。

## 在 CloudWatch 主控台中檢視 記錄
<a name="java-logging-cwconsole"></a>

您可以使用 Amazon CloudWatch 主控台來檢視所有 Lambda 函數調用的日誌。

**若要在 CloudWatch 主控台上檢視日誌**

1. 在 CloudWatch 主控台上開啟[日誌群組頁面](https://console.aws.amazon.com/cloudwatch/home?#logs:)。

1. 選擇您的函數的日誌群組 (**/aws/lambda/*your-function-name***)。

1. 選擇日誌串流

每個日誌串流都會對應至[函式的執行個體](lambda-runtime-environment.md)。當您更新 Lambda 函數，以及建立其他執行個體以處理並行調用時，就會顯示日誌串流。若要尋找特定調用的日誌，建議您使用 檢測函數 AWS X-Ray。X-Ray 會在追蹤內記錄有關請求和日誌串流的詳細資訊。

## 使用 AWS Command Line Interface (AWS CLI) 檢視日誌
<a name="java-logging-cli"></a>

是一種 AWS CLI 開放原始碼工具，可讓您使用命令列 Shell 中的 命令與 AWS 服務互動。若要完成本節中的步驟，您必須擁有 [AWS CLI 版本 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)。

您可以透過 [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html)，使用 `--log-type` 命令選項來擷取要調用的日誌。其回應將包含 `LogResult` 欄位，內含該次調用的 base64 編碼日誌 (最大達 4 KB)。

**Example 擷取日誌 ID**  
下列範例顯示如何從名稱為 `my-function` 的函數的 `LogResult` 欄位來擷取*日誌 ID*。  

```
aws lambda invoke --function-name my-function out --log-type Tail
```
您應該會看到下列輸出：  

```
{
    "StatusCode": 200,
    "LogResult": "U1RBUlQgUmVxdWVzdElkOiA4N2QwNDRiOC1mMTU0LTExZTgtOGNkYS0yOTc0YzVlNGZiMjEgVmVyc2lvb...",
    "ExecutedVersion": "$LATEST"
}
```

**Example 解碼日誌**  
在相同的命令提示中，使用 `base64` 公用程式來解碼日誌。下列範例顯示如何擷取 `my-function` 的 base64 編碼日誌。  

```
aws lambda invoke --function-name my-function out --log-type Tail \
--query 'LogResult' --output text --cli-binary-format raw-in-base64-out | base64 --decode
```
如果您使用的是第 2 AWS CLI 版，則需要 **cli-binary-format**選項。若要讓此成為預設的設定，請執行 `aws configure set cli-binary-format raw-in-base64-out`。若要取得更多資訊，請參閱*《AWS Command Line Interface 使用者指南第 2 版》*中 [AWS CLI 支援的全域命令列選項](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)。  
您應該會看到下列輸出：  

```
START RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8 Version: $LATEST
"AWS_SESSION_TOKEN": "AgoJb3JpZ2luX2VjELj...", "_X_AMZN_TRACE_ID": "Root=1-5d02e5ca-f5792818b6fe8368e5b51d50;Parent=191db58857df8395;Sampled=0"",ask/lib:/opt/lib",
END RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8
REPORT RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8  Duration: 79.67 ms      Billed Duration: 80 ms         Memory Size: 128 MB     Max Memory Used: 73 MB
```
該 `base64` 公用程式可在 Linux、macOS 和 [Ubuntu on Windows](https://docs.microsoft.com/en-us/windows/wsl/install-win10) 上使用。macOS 使用者可能需要使用 `base64 -D`。

**Example get-logs.sh 指令碼**  
在相同的命令提示中，使用下列指令碼下載最後五個日誌事件。該指令碼使用 `sed` 以從輸出檔案移除引述，並休眠 15 秒以使日誌可供使用。輸出包括來自 Lambda 的回應以及來自 `get-log-events` 命令的輸出。  
複製下列程式碼範例的內容，並將您的 Lambda 專案目錄儲存為 `get-logs.sh`。  
如果您使用的是第 2 AWS CLI 版，則需要 **cli-binary-format**選項。若要讓此成為預設的設定，請執行 `aws configure set cli-binary-format raw-in-base64-out`。若要取得更多資訊，請參閱*《AWS Command Line Interface 使用者指南第 2 版》*中 [AWS CLI 支援的全域命令列選項](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)。  

```
#!/bin/bash
aws lambda invoke --function-name my-function --cli-binary-format raw-in-base64-out --payload '{"key": "value"}' out
sed -i'' -e 's/"//g' out
sleep 15
aws logs get-log-events --log-group-name /aws/lambda/my-function --log-stream-name stream1 --limit 5
```

**Example macOS 和 Linux (僅限)**  
在相同的命令提示中，macOS 和 Linux 使用者可能需要執行下列命令，以確保指令碼可執行。  

```
chmod -R 755 get-logs.sh
```

**Example 擷取最後五個記錄事件**  
在相同的命令提示中，執行下列指令碼以取得最後五個日誌事件。  

```
./get-logs.sh
```
您應該會看到下列輸出：  

```
{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}
{
    "events": [
        {
            "timestamp": 1559763003171,
            "message": "START RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf Version: $LATEST\n",
            "ingestionTime": 1559763003309
        },
        {
            "timestamp": 1559763003173,
            "message": "2019-06-05T19:30:03.173Z\t4ce9340a-b765-490f-ad8a-02ab3415e2bf\tINFO\tENVIRONMENT VARIABLES\r{\r  \"AWS_LAMBDA_FUNCTION_VERSION\": \"$LATEST\",\r ...",
            "ingestionTime": 1559763018353
        },
        {
            "timestamp": 1559763003173,
            "message": "2019-06-05T19:30:03.173Z\t4ce9340a-b765-490f-ad8a-02ab3415e2bf\tINFO\tEVENT\r{\r  \"key\": \"value\"\r}\n",
            "ingestionTime": 1559763018353
        },
        {
            "timestamp": 1559763003218,
            "message": "END RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf\n",
            "ingestionTime": 1559763018353
        },
        {
            "timestamp": 1559763003218,
            "message": "REPORT RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf\tDuration: 26.73 ms\tBilled Duration: 27 ms \tMemory Size: 128 MB\tMax Memory Used: 75 MB\t\n",
            "ingestionTime": 1559763018353
        }
    ],
    "nextForwardToken": "f/34783877304859518393868359594929986069206639495374241795",
    "nextBackwardToken": "b/34783877303811383369537420289090800615709599058929582080"
}
```

## 刪除日誌
<a name="java-logging-delete"></a>

當您刪除函數時，不會自動刪除日誌群組。若要避免無限期地儲存日誌，請刪除日誌群組，或[設定保留期間](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/Working-with-log-groups-and-streams.html#SettingLogRetention)，系統會在該時間之後自動刪除日誌。

## 日誌記錄程式碼範例
<a name="java-logging-samples"></a>

本指南的 GitHub 儲存庫包含示範各種日誌記錄組態使用方式的範例應用程式。每個範例應用程式都包含易於部署和清除的指令碼、 AWS SAM 範本和支援資源。

**以 Java 編寫的範例 Lambda 應用程式**
+ [example-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/example-java) – Java 函式，示範如何使用 Lambda 處理訂單。此函數說明如何定義和還原序列化自訂輸入事件物件、使用 AWS SDK 和輸出記錄。
+ [java-basic](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-basic) - 具有單元測試和變數日誌組態的最小 Java 函數集合。
+ [java-events](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-events) - Java 函數集合，其中包含如何處理來自各種服務 (例如 Amazon API Gateway、Amazon SQS 和 Amazon Kinesis) 事件的骨架程式碼。這些函數使用最新版 [aws-lambda-java-events](java-package.md) 程式庫 (3.0.0 及更新版)。這些範例不需要 AWS SDK 做為相依性。
+ [s3-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/s3-java) - 一種 Java 函數，它處理來自 Amazon S3 的通知事件，並使用 Java Class Library (JCL) 以從上傳的映像檔案建立縮圖。
+ [layer-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/layer-java) – 此 Java 函式示範如何使用 Lambda 層，將相依項與核心函式程式碼分離封裝。

`java-basic` 範例應用程式會顯示支援日誌記錄測試的最小日誌記錄組態。處理常式程式碼會使用內容物件提供的 `LambdaLogger` 記錄器。對於測試，應用程式會使用實作具有 Log4j2 記錄器的 `LambdaLogger` 介面的自訂 `TestLogger` 類別。它使用 SLF4J 做為與 AWS SDK 相容的外觀。建置輸出中會排除記錄程式庫，使部署套件不會變太大。

# 在 中檢測 Java 程式碼 AWS Lambda
<a name="java-tracing"></a>

Lambda 與 整合 AWS X-Ray ，以協助您追蹤、偵錯和最佳化 Lambda 應用程式。您可以使用 X-Ray 來追蹤請求，因為它會周遊您應用程式中的資源，其中可能包含 Lambda 函數和其他 AWS 服務。

若要將追蹤資料傳送至 X-Ray，您可以使用以下兩個 SDK 庫之一：
+ [AWS Distro for OpenTelemetry (ADOT)](https://aws.amazon.com/otel) – OpenTelemetry (OTel) SDK 的安全、生產就緒、 AWS支援的分發。
+ [適用於 JAVA 的 AWS X-Ray SDK](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-java.html) – 用於生成追蹤資料並將其傳送至 X-Ray 的 SDK。
+ [Powertools for AWS Lambda (Java)](https://docs.aws.amazon.com/powertools/java/latest/) – 開發人員工具組，用於實作無伺服器最佳實務並提高開發人員速度。

每個 SDK 均提供將遙測資料傳送至 X-Ray 服務的方法。然後，您可以使用 X-Ray 來檢視、篩選應用程式的效能指標並獲得洞察，從而識別問題和進行最佳化的機會。

**重要**  
X-Ray 和 Powertools AWS Lambda SDKs是 提供的緊密整合檢測解決方案的一部分 AWS。ADOT Lambda Layers 是用於追蹤檢測之業界通用標準的一部分，這類檢測一般會收集更多資料，但可能不適用於所有使用案例。您可以使用任一解決方案在 X-Ray 中實作端對端追蹤。若要深入了解如何在兩者之間做選擇，請參閱[在 AWS Distro for OpenTelemetry 和 X-Ray SDK 之間進行選擇](https://docs.aws.amazon.com/xray/latest/devguide/xray-instrumenting-your-app.html#xray-instrumenting-choosing)。

**Topics**
+ [使用 Powertools for AWS Lambda (Java) 和 AWS SAM 進行追蹤](#java-tracing-sam)
+ [使用 Powertools for AWS Lambda (Java) 和 AWS CDK 進行追蹤](#java-tracing-cdk)
+ [使用 ADOT 來檢測您的 Java 函數](#java-adot)
+ [使用 X-Ray SDK 來檢測 Java 功能](#java-xray-sdk)
+ [透過 Lambda 主控台來啟用追蹤](#java-tracing-console)
+ [透過 Lambda API 啟用追蹤](#java-tracing-api)
+ [使用 啟用追蹤 CloudFormation](#java-tracing-cloudformation)
+ [解讀 X-Ray 追蹤](#java-tracing-interpretation)
+ [將執行時間相依項存放存在層中 (X-Ray SDK)](#java-tracing-layers)
+ [樣本應用程式中的 X-Ray 追蹤 (X-Ray SDK)](#java-tracing-samples)

## 使用 Powertools for AWS Lambda (Java) 和 AWS SAM 進行追蹤
<a name="java-tracing-sam"></a>

請依照下列步驟，使用 下載、建置和部署範例 Hello World Java 應用程式，並整合 [Powertools for AWS Lambda (Java)](https://docs.powertools.aws.dev/lambda-java) 模組 AWS SAM。此應用程式實作了基本 API 後端，並使用 Powertools 發送日誌、指標和追蹤。其包含 Amazon API Gateway 端點和 Lambda 函數。當您將 GET 請求傳送至 API Gateway 端點時，Lambda 函數會調用、使用內嵌指標格式將日誌和指標傳送至 CloudWatch，並將追蹤傳送至 AWS X-Ray。該函數會傳回 `hello world` 訊息。

**先決條件**

若要完成本節中的步驟，您必須執行下列各項：
+ Java 11 或更新版本
+ [AWS CLI 第 2 版](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS SAM CLI 1.75 版或更新版本。](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)如果您有較舊版本的 AWS SAM CLI，請參閱[升級 AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/manage-sam-cli-versions.html#manage-sam-cli-versions-upgrade)。

**部署範例 AWS SAM 應用程式**

1. 使用 Hello World Java 範本來初始化應用程式。

   ```
   sam init --app-template hello-world-powertools-java --name sam-app --package-type Zip --runtime java11 --no-tracing
   ```

1. 建置應用程式。

   ```
   cd sam-app && sam build
   ```

1. 部署應用程式。

   ```
   sam deploy --guided
   ```

1. 依照螢幕上的提示操作。若要接受互動體驗中提供的預設選項，請按下 `Enter`。
**注意**  
對於 **HelloWorldFunction may not have authorization defined, Is this okay?**，確保輸入 `y`。

1. 取得已部署應用程式的 URL：

   ```
   aws cloudformation describe-stacks --stack-name sam-app --query 'Stacks[0].Outputs[?OutputKey==`HelloWorldApi`].OutputValue' --output text
   ```

1. 調用 API 端點：

   ```
   curl -X GET <URL_FROM_PREVIOUS_STEP>
   ```

   成功的話，您將會看到以下回應：

   ```
   {"message":"hello world"}
   ```

1. 若要取得函數的追蹤，請執行 [sam 追蹤](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-traces.html)。

   ```
   sam traces
   ```

   追蹤輸出如下：

   ```
   New XRay Service Graph
     Start time: 2025-02-03 14:31:48+01:00
     End time: 2025-02-03 14:31:48+01:00
     Reference Id: 0 - (Root) AWS::Lambda - sam-app-HelloWorldFunction-y9Iu1FLJJBGD - Edges: []
      Summary_statistics:
        - total requests: 1
        - ok count(2XX): 1
        - error count(4XX): 0
        - fault count(5XX): 0
        - total response time: 5.587
     Reference Id: 1 - client - sam-app-HelloWorldFunction-y9Iu1FLJJBGD - Edges: [0]
      Summary_statistics:
        - total requests: 0
        - ok count(2XX): 0
        - error count(4XX): 0
        - fault count(5XX): 0
        - total response time: 0
   
   XRay Event [revision 3] at (2025-02-03T14:31:48.500000) with id (1-63dd0cc4-3c869dec72a586875da39777) and duration (5.603s)
    - 5.587s - sam-app-HelloWorldFunction-y9Iu1FLJJBGD [HTTP: 200]
    - 4.053s - sam-app-HelloWorldFunction-y9Iu1FLJJBGD
      - 1.181s - Initialization
      - 4.037s - Invocation
        - 1.981s - ## handleRequest
          - 1.840s - ## getPageContents
      - 0.000s - Overhead
   ```

1. 這是可透過網際網路存取的公有 API 端點。建議您在測試後刪除端點。

   ```
   sam delete
   ```

## 使用 Powertools for AWS Lambda (Java) 和 AWS CDK 進行追蹤
<a name="java-tracing-cdk"></a>

請依照下列步驟，使用 下載、建置和部署範例 Hello World Java 應用程式，並整合 [Powertools for AWS Lambda (Java)](https://docs.powertools.aws.dev/lambda-java) 模組 AWS CDK。此應用程式實作了基本 API 後端，並使用 Powertools 發送日誌、指標和追蹤。其包含 Amazon API Gateway 端點和 Lambda 函數。當您將 GET 請求傳送至 API Gateway 端點時，Lambda 函數會調用、使用內嵌指標格式將日誌和指標傳送至 CloudWatch，並將追蹤傳送至 AWS X-Ray。函數會傳回 hello world 訊息。

**先決條件**

若要完成本節中的步驟，您必須執行下列各項：
+ Java 11 或更新版本
+ [AWS CLI 第 2 版](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS CDK 第 2 版](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_prerequisites)
+ [AWS SAM CLI 1.75 版或更新版本。](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)如果您有較舊版本的 AWS SAM CLI，請參閱[升級 AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/manage-sam-cli-versions.html#manage-sam-cli-versions-upgrade)。

**部署範例 AWS CDK 應用程式**

1. 為您的新應用程式建立專案目錄。

   ```
   mkdir hello-world
   cd hello-world
   ```

1. 初始化應用程式。

   ```
   cdk init app --language java
   ```

1. 使用以下命令來建立 Maven 專案：

   ```
   mkdir app
   cd app
   mvn archetype:generate -DgroupId=helloworld -DartifactId=Function -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
   ```

1. 在 `hello-world\app\Function` 目錄中開啟 `pom.xml`，並將現有程式碼替換為下面的程式碼，其中包括 Powertools 的相依性和 Maven 外掛程式。

   ```
   <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <groupId>helloworld</groupId>
     <artifactId>Function</artifactId>
     <packaging>jar</packaging>
     <version>1.0-SNAPSHOT</version>
     <name>Function</name>
     <url>http://maven.apache.org</url>
   <properties>
       <maven.compiler.source>11</maven.compiler.source>
       <maven.compiler.target>11</maven.compiler.target>
       <log4j.version>2.17.2</log4j.version>
   </properties>
       <dependencies>
           <dependency>
               <groupId>junit</groupId>
               <artifactId>junit</artifactId>
               <version>3.8.1</version>
               <scope>test</scope>
           </dependency>
           <dependency>
               <groupId>software.amazon.lambda</groupId>
               <artifactId>powertools-tracing</artifactId>
               <version>1.3.0</version>
           </dependency>
           <dependency>
               <groupId>software.amazon.lambda</groupId>
               <artifactId>powertools-metrics</artifactId>
               <version>1.3.0</version>
           </dependency>
           <dependency>
               <groupId>software.amazon.lambda</groupId>
               <artifactId>powertools-logging</artifactId>
               <version>1.3.0</version>
           </dependency>
           <dependency>
               <groupId>com.amazonaws</groupId>
               <artifactId>aws-lambda-java-core</artifactId>
               <version>1.2.2</version>
           </dependency>
           <dependency>
               <groupId>com.amazonaws</groupId>
               <artifactId>aws-lambda-java-events</artifactId>
               <version>3.11.1</version>
           </dependency>
     </dependencies>
   <build>
       <plugins>
           <plugin>
               <groupId>org.codehaus.mojo</groupId>
               <artifactId>aspectj-maven-plugin</artifactId>
               <version>1.14.0</version>
               <configuration>
                   <source>${maven.compiler.source}</source>
                   <target>${maven.compiler.target}</target>
                   <complianceLevel>${maven.compiler.target}</complianceLevel>
                   <aspectLibraries>
                       <aspectLibrary>
                           <groupId>software.amazon.lambda</groupId>
                           <artifactId>powertools-tracing</artifactId>
                       </aspectLibrary>
                       <aspectLibrary>
                           <groupId>software.amazon.lambda</groupId>
                           <artifactId>powertools-metrics</artifactId>
                       </aspectLibrary>
                       <aspectLibrary>
                           <groupId>software.amazon.lambda</groupId>
                           <artifactId>powertools-logging</artifactId>
                       </aspectLibrary>
                   </aspectLibraries>
               </configuration>
               <executions>
                   <execution>
                       <goals>
                           <goal>compile</goal>
                       </goals>
                   </execution>
               </executions>
           </plugin>
           <plugin>
                   <groupId>org.apache.maven.plugins</groupId>
                   <artifactId>maven-shade-plugin</artifactId>
                   <version>3.4.1</version>
                   <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>
                               <createDependencyReducedPom>false</createDependencyReducedPom>
                               <finalName>function</finalName>
   
                           </configuration>
                       </execution>
                   </executions>
                   <dependencies>
                       <dependency>
                           <groupId>com.github.edwgiz</groupId>
                           <artifactId>maven-shade-plugin.log4j2-cachefile-transformer</artifactId>
                           <version>2.15</version>
                       </dependency>
                   </dependencies>
           </plugin>
       </plugins>
   </build>
   </project>
   ```

1. 建立 `hello-world\app\src\main\resource` 目錄並為日誌組態建立 `log4j.xml`。

   ```
   mkdir -p src/main/resource
   cd src/main/resource
   touch log4j.xml
   ```

1. 開啟 `log4j.xml` 並新增以下程式碼。

   ```
   <?xml version="1.0" encoding="UTF-8"?>
   <Configuration>
       <Appenders>
           <Console name="JsonAppender" target="SYSTEM_OUT">
               <JsonTemplateLayout eventTemplateUri="classpath:LambdaJsonLayout.json" />
           </Console>
       </Appenders>
       <Loggers>
           <Logger name="JsonLogger" level="INFO" additivity="false">
               <AppenderRef ref="JsonAppender"/>
           </Logger>
           <Root level="info">
               <AppenderRef ref="JsonAppender"/>
           </Root>
       </Loggers>
   </Configuration>
   ```

1. 從 `hello-world\app\Function\src\main\java\helloworld` 目錄中開啟 `App.java`，並將現有程式碼替換為下面的程式碼。這是 Lambda 函數的程式碼。

   ```
   package helloworld;
   
   import java.io.BufferedReader;
   import java.io.IOException;
   import java.io.InputStreamReader;
   import java.net.URL;
   import java.util.HashMap;
   import java.util.Map;
   import java.util.stream.Collectors;
   
   import com.amazonaws.services.lambda.runtime.Context;
   import com.amazonaws.services.lambda.runtime.RequestHandler;
   import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
   import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
   import org.apache.logging.log4j.LogManager;
   import org.apache.logging.log4j.Logger;
   import software.amazon.lambda.powertools.logging.Logging;
   import software.amazon.lambda.powertools.metrics.Metrics;
   import software.amazon.lambda.powertools.tracing.CaptureMode;
   import software.amazon.lambda.powertools.tracing.Tracing;
   
   import static software.amazon.lambda.powertools.tracing.CaptureMode.*;
   
   /**
    * Handler for requests to Lambda function.
    */
   public class App implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
       Logger log = LogManager.getLogger(App.class);
   
   
       @Logging(logEvent = true)
       @Tracing(captureMode = DISABLED)
       @Metrics(captureColdStart = true)
       public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
           Map<String, String> headers = new HashMap<>();
           headers.put("Content-Type", "application/json");
           headers.put("X-Custom-Header", "application/json");
   
           APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent()
                   .withHeaders(headers);
           try {
               final String pageContents = this.getPageContents("https://checkip.amazonaws.com");
               String output = String.format("{ \"message\": \"hello world\", \"location\": \"%s\" }", pageContents);
   
               return response
                       .withStatusCode(200)
                       .withBody(output);
           } catch (IOException e) {
               return response
                       .withBody("{}")
                       .withStatusCode(500);
           }
       }
       @Tracing(namespace = "getPageContents")
       private String getPageContents(String address) throws IOException {
           log.info("Retrieving {}", address);
           URL url = new URL(address);
           try (BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()))) {
               return br.lines().collect(Collectors.joining(System.lineSeparator()));
           }
       }
   }
   ```

1. 從 `hello-world\src\main\java\com\myorg` 目錄中開啟 `HelloWorldStack.java`，並將現有程式碼替換為下面的程式碼。此程式碼會使用 [Lambda 建構函數](https://docs.aws.amazon.com/cdk/api/v1/java/aws_cdk.aws_lambda.html)和 [ApiGatewayv2 建構函數](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigatewayv2-readme.html)來建立 REST API 和 Lambda 函數。

   ```
   package com.myorg;
   
   import software.amazon.awscdk.*;
   import software.amazon.awscdk.services.apigatewayv2.alpha.*;
   import software.amazon.awscdk.services.apigatewayv2.integrations.alpha.HttpLambdaIntegration;
   import software.amazon.awscdk.services.apigatewayv2.integrations.alpha.HttpLambdaIntegrationProps;
   import software.amazon.awscdk.services.lambda.Code;
   import software.amazon.awscdk.services.lambda.Function;
   import software.amazon.awscdk.services.lambda.FunctionProps;
   import software.amazon.awscdk.services.lambda.Runtime;
   import software.amazon.awscdk.services.lambda.Tracing;
   import software.amazon.awscdk.services.logs.RetentionDays;
   import software.amazon.awscdk.services.s3.assets.AssetOptions;
   import software.constructs.Construct;
   
   import java.util.Arrays;
   import java.util.List;
   
   import static java.util.Collections.singletonList;
   import static software.amazon.awscdk.BundlingOutput.ARCHIVED;
   
   public class HelloWorldStack extends Stack {
       public HelloWorldStack(final Construct scope, final String id) {
           this(scope, id, null);
       }
   
       public HelloWorldStack(final Construct scope, final String id, final StackProps props) {
           super(scope, id, props);
   
           List<String> functionPackagingInstructions = Arrays.asList(
                   "/bin/sh",
                   "-c",
                   "cd Function " +
                           "&& mvn clean install " +
                           "&& cp /asset-input/Function/target/function.jar /asset-output/"
           );
           BundlingOptions.Builder builderOptions = BundlingOptions.builder()
                   .command(functionPackagingInstructions)
                   .image(Runtime.JAVA_11.getBundlingImage())
                   .volumes(singletonList(
                           // Mount local .m2 repo to avoid download all the dependencies again inside the container
                           DockerVolume.builder()
                                   .hostPath(System.getProperty("user.home") + "/.m2/")
                                   .containerPath("/root/.m2/")
                                   .build()
                   ))
                   .user("root")
                   .outputType(ARCHIVED);
   
           Function function = new Function(this, "Function", FunctionProps.builder()
                   .runtime(Runtime.JAVA_11)
                   .code(Code.fromAsset("app", AssetOptions.builder()
                           .bundling(builderOptions
                                   .command(functionPackagingInstructions)
                                   .build())
                           .build()))
                   .handler("helloworld.App::handleRequest")
                   .memorySize(1024)
                   .tracing(Tracing.ACTIVE)
                   .timeout(Duration.seconds(10))
                   .logRetention(RetentionDays.ONE_WEEK)
                   .build());
   
           HttpApi httpApi = new HttpApi(this, "sample-api", HttpApiProps.builder()
                   .apiName("sample-api")
                   .build());
   
           httpApi.addRoutes(AddRoutesOptions.builder()
                   .path("/")
                   .methods(singletonList(HttpMethod.GET))
                   .integration(new HttpLambdaIntegration("function", function, HttpLambdaIntegrationProps.builder()
                           .payloadFormatVersion(PayloadFormatVersion.VERSION_2_0)
                           .build()))
                   .build());
   
           new CfnOutput(this, "HttpApi", CfnOutputProps.builder()
                   .description("Url for Http Api")
                   .value(httpApi.getApiEndpoint())
                   .build());
       }
   }
   ```

1. 從 `hello-world` 目錄中開啟 `pom.xml`，並將現有程式碼替換為下面的程式碼。

   ```
   <?xml version="1.0" encoding="UTF-8"?>
   <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
            xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
       <modelVersion>4.0.0</modelVersion>
   
       <groupId>com.myorg</groupId>
       <artifactId>hello-world</artifactId>
       <version>0.1</version>
   
       <properties>
           <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
           <cdk.version>2.70.0</cdk.version>
           <constructs.version>[10.0.0,11.0.0)</constructs.version>
           <junit.version>5.7.1</junit.version>
       </properties>
   
       <build>
           <plugins>
               <plugin>
                   <groupId>org.apache.maven.plugins</groupId>
                   <artifactId>maven-compiler-plugin</artifactId>
                   <version>3.8.1</version>
                   <configuration>
                       <source>1.8</source>
                       <target>1.8</target>
                   </configuration>
               </plugin>
   
               <plugin>
                   <groupId>org.codehaus.mojo</groupId>
                   <artifactId>exec-maven-plugin</artifactId>
                   <version>3.0.0</version>
                   <configuration>
                       <mainClass>com.myorg.HelloWorldApp</mainClass>
                   </configuration>
               </plugin>
           </plugins>
       </build>
   
       <dependencies>
           <!-- AWS Cloud Development Kit -->
           <dependency>
               <groupId>software.amazon.awscdk</groupId>
               <artifactId>aws-cdk-lib</artifactId>
               <version>${cdk.version}</version>
           </dependency>
           <dependency>
               <groupId>software.constructs</groupId>
               <artifactId>constructs</artifactId>
               <version>${constructs.version}</version>
           </dependency>
           <dependency>
             <groupId>org.junit.jupiter</groupId>
             <artifactId>junit-jupiter</artifactId>
             <version>${junit.version}</version>
             <scope>test</scope>
           </dependency>
           <dependency>
               <groupId>software.amazon.awscdk</groupId>
               <artifactId>apigatewayv2-alpha</artifactId>
               <version>${cdk.version}-alpha.0</version>
           </dependency>
           <dependency>
               <groupId>software.amazon.awscdk</groupId>
               <artifactId>apigatewayv2-integrations-alpha</artifactId>
               <version>${cdk.version}-alpha.0</version>
           </dependency>
       </dependencies>
   </project>
   ```

1. 確保您位於 `hello-world` 目錄中並部署您的應用程式。

   ```
   cdk deploy
   ```

1. 取得已部署應用程式的 URL：

   ```
   aws cloudformation describe-stacks --stack-name HelloWorldStack --query 'Stacks[0].Outputs[?OutputKey==`HttpApi`].OutputValue' --output text
   ```

1. 調用 API 端點：

   ```
   curl -X GET <URL_FROM_PREVIOUS_STEP>
   ```

   成功的話，您將會看到以下回應：

   ```
   {"message":"hello world"}
   ```

1. 若要取得函數的追蹤，請執行 [sam 追蹤](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-traces.html)。

   ```
   sam traces
   ```

   追蹤輸出如下：

   ```
   New XRay Service Graph
     Start time: 2025-02-03 14:59:50+00:00
     End time: 2025-02-03 14:59:50+00:00
     Reference Id: 0 - (Root) AWS::Lambda - sam-app-HelloWorldFunction-YBg8yfYtOc9j - Edges: [1]
      Summary_statistics:
        - total requests: 1
        - ok count(2XX): 1
        - error count(4XX): 0
        - fault count(5XX): 0
        - total response time: 0.924
     Reference Id: 1 - AWS::Lambda::Function - sam-app-HelloWorldFunction-YBg8yfYtOc9j - Edges: []
      Summary_statistics:
        - total requests: 1
        - ok count(2XX): 1
        - error count(4XX): 0
        - fault count(5XX): 0
        - total response time: 0.016
     Reference Id: 2 - client - sam-app-HelloWorldFunction-YBg8yfYtOc9j - Edges: [0]
      Summary_statistics:
        - total requests: 0
        - ok count(2XX): 0
        - error count(4XX): 0
        - fault count(5XX): 0
        - total response time: 0
   
   XRay Event [revision 1] at (2025-02-03T14:59:50.204000) with id (1-63dd2166-434a12c22e1307ff2114f299) and duration (0.924s)
    - 0.924s - sam-app-HelloWorldFunction-YBg8yfYtOc9j [HTTP: 200]
    - 0.016s - sam-app-HelloWorldFunction-YBg8yfYtOc9j
      - 0.739s - Initialization
      - 0.016s - Invocation
        - 0.013s - ## lambda_handler
          - 0.000s - ## app.hello
      - 0.000s - Overhead
   ```

1. 這是可透過網際網路存取的公有 API 端點。建議您在測試後刪除端點。

   ```
   cdk destroy
   ```

## 使用 ADOT 來檢測您的 Java 函數
<a name="java-adot"></a>

ADOT 提供全受管 Lambda [層](chapter-layers.md)，包含使用 OTel SDK 收集遙測資料所需的一切內容。透過取用此層，您可以檢測 Lambda 函數，而無需修改任何函數程式碼。您還可以將層設定為對 OTel 進行自訂初始化。如需詳細資訊，請參閱 ADOT 文件中的[針對 Lambda 上的 ADOT 收集器進行自訂組態設定](https://aws-otel.github.io/docs/getting-started/lambda#custom-configuration-for-the-adot-collector-on-lambda)。

對於 Java 執行時間，您可以選擇要取用的兩層：
+ **AWS ADOT Java （自動檢測代理程式） 的 受管 Lambda 層** – 此層會在啟動時自動轉換函數程式碼，以收集追蹤資料。如需有關如何搭配 ADOT Java 代理程式取用此層的詳細指示，請參閱 ADOT 文件中的[適用於 Java 的AWS Distro for OpenTelemetry Lambda 支援 (自動檢測代理程式)](https://aws-otel.github.io/docs/getting-started/lambda/lambda-java-auto-instr)。
+ **AWS 適用於 ADOT Java 的 受管 Lambda 層** – 此層還提供 Lambda 函數的內建檢測，但需要一些手動程式碼變更才能初始化 OTel SDK。如需有關如何取用此層的詳細指示，請參閱 ADOT 文件中的[適用於 Java 的AWS Distro for OpenTelemetry Lambda 支援](https://aws-otel.github.io/docs/getting-started/lambda/lambda-java)。

## 使用 X-Ray SDK 來檢測 Java 功能
<a name="java-xray-sdk"></a>

若要記錄函數對應用程式中其他資源和服務呼叫的資料，請將適用於 Java 的 X-Ray 開發套件新增至您的建置組態。下列範例顯示 Gradle 建置組態，其中包含啟用 AWS SDK for Java 2.x 用戶端自動檢測的程式庫。

**Example [build.gradle](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/s3-java/build.gradle) - 追蹤相依性**  

```
dependencies {
    implementation platform('software.amazon.awssdk:bom:2.16.1')
    implementation platform('com.amazonaws:aws-xray-recorder-sdk-bom:2.11.0')
    ...
    implementation 'com.amazonaws:aws-xray-recorder-sdk-core'
    implementation 'com.amazonaws:aws-xray-recorder-sdk-aws-sdk'
    implementation 'com.amazonaws:aws-xray-recorder-sdk-aws-sdk-v2-instrumentor'
    ...
}
```

新增正確的相依項並完成必要的程式碼變更後，請透過 Lambda 主控台或 API 在函數組態中啟用追蹤功能。

## 透過 Lambda 主控台來啟用追蹤
<a name="java-tracing-console"></a>

若要使用控制台在 Lambda 函數上切換主動追蹤，請按照下列步驟操作：

**開啟主動追蹤**

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇一個函數。

1. 選擇**組態**，然後選擇**監控和操作工具**。

1. 在**其他監控工具**欄位中，選擇**編輯**。

1. 在 **CloudWatch Application Signals 和 AWS X-Ray** 下，選擇**啟用** **Lambda 服務追蹤**。

1. 選擇**儲存**。

## 透過 Lambda API 啟用追蹤
<a name="java-tracing-api"></a>

使用 AWS CLI 或 AWS SDK 在 Lambda 函數上設定追蹤，請使用下列 API 操作：
+ [UpdateFunctionConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateFunctionConfiguration.html)
+ [GetFunctionConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_GetFunctionConfiguration.html)
+ [CreateFunction](https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html)

下列範例 AWS CLI 命令會在名為 **my-function** 的函數上啟用主動追蹤。

```
aws lambda update-function-configuration --function-name my-function \
--tracing-config Mode=Active
```

追蹤模式是您發布函數版本時版本特定組態的一部分。您無法變更已發佈版本上的追蹤模式。

## 使用 啟用追蹤 CloudFormation
<a name="java-tracing-cloudformation"></a>

若要在 CloudFormation 範本中的 `AWS::Lambda::Function` 資源上啟用追蹤，請使用 `TracingConfig` 屬性。

**Example [function-inline.yml](https://github.com/awsdocs/aws-lambda-developer-guide/blob/master/templates/function-inline.yml) - 追蹤組態**  

```
Resources:
  function:
    Type: [AWS::Lambda::Function](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html)
    Properties:
      TracingConfig:
        Mode: Active
      ...
```

對於 AWS Serverless Application Model (AWS SAM) `AWS::Serverless::Function` 資源，請使用 `Tracing` 屬性。

**Example [template.yml](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/blank-nodejs/template.yml) - 追蹤組態**  

```
Resources:
  function:
    Type: [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html)
    Properties:
      Tracing: Active
      ...
```

## 解讀 X-Ray 追蹤
<a name="java-tracing-interpretation"></a>

您的函數需要將追蹤資料上傳至 X-Ray 的許可。當您在 Lambda 主控台中啟用追蹤時，Lambda 會將必要的許可新增至函數的[執行角色](lambda-intro-execution-role.md)。否則，請將 [AWSXRayDaemonWriteAccess](https://console.aws.amazon.com/iam/home#/policies/arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess) 政策新增至執行角色。

設定主動追蹤之後，您可以透過應用程式來觀察特定請求。[X-Ray 服務圖](https://docs.aws.amazon.com/xray/latest/devguide/aws-xray.html#xray-concepts-servicegraph)顯示了有關應用程式及其所有元件的資訊。下列範例顯示了一個具有兩個函數的應用程式。主要函式會處理事件，有時會傳回錯誤。頂端的第二個函數會處理出現在第一個日誌群組中的錯誤，並使用 AWS SDK 呼叫 X-Ray、Amazon Simple Storage Service (Amazon S3) 和 Amazon CloudWatch Logs。

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/sample-errorprocessor-servicemap.png)


X-Ray 無法追蹤應用程式的所有請求。X-Ray 會套用取樣演算法以確保追蹤的效率，同時仍提供所有請求的代表範本。取樣率為每秒 1 次請求和 5% 的額外請求。不能針對函數設定 X-Ray 取樣率。

在 X-Ray 中，*追蹤*會記錄一或多個*服務*所處理之要求的相關資訊。Lambda 會在每個追蹤上記錄 2 個區段，這會在服務圖表上建立兩個節點。下圖反白顯示了這兩個節點：

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/xray-servicemap-function.png)


左側第一個節點代表接收調用請求的 Lambda 服務。第二個節點代表您特定的 Lambda 函數。下列範例顯示了具有這 2 個區段的追蹤。兩者都被命名為 **my-function**，但其中之一的來源為 `AWS::Lambda`，而另一個的來源為 `AWS::Lambda::Function`。如果 `AWS::Lambda` 區段顯示錯誤，Lambda 服務就會出現問題。如果 `AWS::Lambda::Function` 區段顯示錯誤，表示您的函數出現了問題。

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/V2_sandbox_images/my-function-2-v1.png)


此範例會展開 `AWS::Lambda::Function` 區段以顯示其三個子區段：

**注意**  
AWS 目前正在對 Lambda 服務實作變更。由於這些變更，您可能會看到系統日誌訊息的結構和內容，與 AWS 帳戶中不同 Lambda 函數發出的追蹤區段之間存在細微差異。  
此處顯示的追蹤範例說明了舊式函數區段。下列段落說明了舊式和新式區段之間的差異。  
這些變化將在未來幾週內實作，除中國和 GovCloud 區域以外，所有 AWS 區域 中的所有函數都會轉換至使用新格式的日誌訊息和追蹤區段。

舊式函數區段包含下列子區段：
+ **初始化** - 表示載入函數和執行[初始化程式碼](foundation-progmodel.md)所花費的時間。只有函數的每個執行個體所處理的第一個事件會顯示此子區段。
+ **調用** – 表示執行處理常式程式碼所花費的時間。
+ **額外負荷** - 表示 Lambda 執行期為做好準備以處理下一個事件所花費的時間。

新式函數區段不包含 `Invocation` 子區段。相反地，客戶子區段會直接連接至函數區段。如需舊式和新式函數區段結構的詳細資訊，請參閱[了解 X-Ray 追蹤](services-xray.md#services-xray-traces)。

**注意**  
[Lambda SnapStart](snapstart.md) 函數還包括一個 `Restore` 子區段。`Restore` 子區段會顯示 Lambda 還原快照、載入執行時期和執行任何還原後[執行時期勾點](snapstart-runtime-hooks.md)所需的時間。還原快照的程序可能包括在 MicroVM 以外的活動上花費的時間。此時間在 `Restore` 子區段中報告。您不需要為在 MicroVM 外還原快照所花費的時間付費。

您也可以檢測 HTTP 用戶端、記錄 SQL 查詢，以及建立具有註釋和中繼資料的自訂子區段。如需詳細資訊，請參閱《AWS X-Ray 開發人員指南》**中的 [適用於 JAVA 的 AWS X-Ray SDK](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-java.html)。

**定價**  
您可以在每月免費使用 X-Ray 追蹤，最高可達特定限制，作為 AWS 免費方案的一部分。達到閾值後，X-Ray 會收取追蹤儲存及擷取的費用。如需詳細資訊，請參閱 [AWS X-Ray 定價](https://aws.amazon.com/xray/pricing/)。

## 將執行時間相依項存放存在層中 (X-Ray SDK)
<a name="java-tracing-layers"></a>

如果您使用 X-Ray 開發套件來檢測函數程式碼的 AWS SDK 用戶端，您的部署套件可能會變得相當大。為了避免每次更新函數程式碼時上傳執行時間相依性，請將 X-Ray SDK 封裝在一個 [Lambda 層](chapter-layers.md)中。

下面的範例顯示了可存放適用於 Java 的 適用於 Java 的 AWS SDK 和 X-Ray SDK 的 `AWS::Serverless::LayerVersion` 資源。

**Example [template.yml](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/blank-java/template.yml) - 相依性層**  

```
Resources:
  function:
    Type: [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html)
    Properties:
      CodeUri: build/distributions/blank-java.zip
      Tracing: Active
      Layers:
        - !Ref libs
      ...
  libs:
    Type: [AWS::Serverless::LayerVersion](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-layerversion.html)
    Properties:
      LayerName: blank-java-lib
      Description: Dependencies for the blank-java sample app.
      ContentUri: build/blank-java-lib.zip
      CompatibleRuntimes:
        - java25
```

透過此組態，您只有在變更執行時間相依性時才會更新程式庫層。由於函數部署套件僅含有您的程式碼，因此有助於減少上傳時間。

為相依性建立層需要建置配置變更，才能在部署之前產生層存檔。如需使用範例，請參閱 GitHub 上的 [java-basic](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-basic) 範例應用程式。

## 樣本應用程式中的 X-Ray 追蹤 (X-Ray SDK)
<a name="java-tracing-samples"></a>

本指南的 GitHub 儲存庫包含示範 X-Ray 追蹤使用方式的範例應用程式。每個範例應用程式都包含易於部署和清除的指令碼、 AWS SAM 範本和支援資源。

**以 Java 編寫的範例 Lambda 應用程式**
+ [example-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/example-java) – Java 函式，示範如何使用 Lambda 處理訂單。此函數說明如何定義和還原序列化自訂輸入事件物件、使用 AWS SDK 和輸出記錄。
+ [java-basic](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-basic) - 具有單元測試和變數日誌組態的最小 Java 函數集合。
+ [java-events](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-events) - Java 函數集合，其中包含如何處理來自各種服務 (例如 Amazon API Gateway、Amazon SQS 和 Amazon Kinesis) 事件的骨架程式碼。這些函數使用最新版 [aws-lambda-java-events](java-package.md) 程式庫 (3.0.0 及更新版)。這些範例不需要 AWS SDK 做為相依性。
+ [s3-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/s3-java) - 一種 Java 函數，它處理來自 Amazon S3 的通知事件，並使用 Java Class Library (JCL) 以從上傳的映像檔案建立縮圖。
+ [layer-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/layer-java) – 此 Java 函式示範如何使用 Lambda 層，將相依項與核心函式程式碼分離封裝。

所有範例應用程式都已啟用 Lambda 函數的主動追蹤功能。例如，`s3-java`應用程式會顯示 AWS SDK for Java 2.x 用戶端的自動檢測、測試的區段管理、自訂子區段，以及使用 Lambda 層來存放執行時間相依性。

# 的 Java 範例應用程式 AWS Lambda
<a name="java-samples"></a>

本指南的 GitHub 儲存庫提供示範在 中使用 Java 的範例應用程式 AWS Lambda。每個範例應用程式都包含易於部署和清除的指令碼、 CloudFormation 範本和支援資源。

**以 Java 編寫的範例 Lambda 應用程式**
+ [example-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/example-java) – Java 函式，示範如何使用 Lambda 處理訂單。此函數說明如何定義和還原序列化自訂輸入事件物件、使用 AWS SDK 和輸出記錄。
+ [java-basic](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-basic) - 具有單元測試和變數日誌組態的最小 Java 函數集合。
+ [java-events](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-events) - Java 函數集合，其中包含如何處理來自各種服務 (例如 Amazon API Gateway、Amazon SQS 和 Amazon Kinesis) 事件的骨架程式碼。這些函數使用最新版 [aws-lambda-java-events](java-package.md) 程式庫 (3.0.0 及更新版)。這些範例不需要 AWS SDK 做為相依性。
+ [s3-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/s3-java) - 一種 Java 函數，它處理來自 Amazon S3 的通知事件，並使用 Java Class Library (JCL) 以從上傳的映像檔案建立縮圖。
+ [layer-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/layer-java) – 此 Java 函式示範如何使用 Lambda 層，將相依項與核心函式程式碼分離封裝。

**在 Lambda 上執行熱門 Java 框架**
+ [spring-cloud-function-samples](https://github.com/spring-cloud/spring-cloud-function/tree/3.2.x/spring-cloud-function-samples/function-sample-aws) – 來自 Spring 的範例，說明如何使用 [Spring Cloud Function](https://spring.io/projects/spring-cloud-function) 架構來建立 AWS Lambda 函數。
+ [Serverless Spring Boot Application 示範](https://github.com/aws-samples/serverless-java-frameworks-samples/tree/main/springboot) – 此範例展示如何在使用 (或不使用) SnapStart 的受管 Java 執行期中設定 Spring Boot 應用程式，或使用自訂執行期做為 GraalVM 原生映像檔。
+ [Serverless Micronaut Application 示範](https://github.com/aws-samples/serverless-java-frameworks-samples/tree/main/micronaut) – 此範例展示如何在使用 (或不使用) SnapStart 的受管 Java 執行期中使用 Micronaut，或使用自訂執行期做為 GraalVM 原生映像檔。請參閱《[Micronaut/Lambda 指南](https://guides.micronaut.io/latest/tag-lambda.html)》以進一步瞭解。
+ [Serverless Quarkus Application 示範](https://github.com/aws-samples/serverless-java-frameworks-samples/tree/main/quarkus) – 此範例展示如何在使用 (或不使用) SnapStart 的受管 Java 執行期中使用 Quarkus，或使用自訂執行期做為 GraalVM 原生映像檔。請參閱《[Quarkus/Lambda 指南](https://quarkus.io/guides/aws-lambda)》和《[Quarkus/SnapStart 指南](https://quarkus.io/guides/aws-lambda-snapstart)》以進一步瞭解。

若您不熟悉 Java 中的 Lambda 函數，請從 `java-basic` 範例開始。若要開始使用 Lambda 事件來源，請參閱 `java-events` 範例。這兩個範例集都顯示使用 Lambda 的 Java 程式庫、環境變數、 AWS SDK 和 AWS X-Ray SDK。這些範例需要最少的設定，不到一分鐘的時間就可以從命令列完成部署。