

# Java를 사용하여 Lambda 함수 빌드
<a name="lambda-java"></a>

AWS Lambda에서 Java 코드를 실행할 수 있습니다. Lambda는 이벤트 처리를 위해 코드를 실행하는 Java를 위한 [런타임](lambda-runtimes.md)을 제공합니다. 코드는 사용자가 관리하는 AWS Identity and Access Management(IAM) 역할의 AWS 자격 증명이 포함된 Amazon Linux 환경에서 실행됩니다.

Lambda는 다음과 같은 Java 런타임을 지원합니다.<a name="java-runtimes"></a>


| 이름 | 식별자 | 운영 체제 | 사용 중단 날짜 | 블록 함수 생성 | 블록 함수 업데이트 | 
| --- | --- | --- | --- | --- | --- | 
|  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) – 현재 호출의 요청 ID를 [함수 로그](java-logging.md)에 추가하는 데 사용할 수 있는 Apache Log4j 2용 appender 라이브러리입니다.
+ [AWS SDK for Java 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가 아닌 API 구성 요소는 변경되거나 업데이트 시 제거될 수 있으며, 이로 인해 애플리케이션이 중단될 수 있습니다.

**Java 함수를 만들려면**

1. [Lambda 콘솔](https://console.aws.amazon.com/lambda)을 엽니다.

1. **함수 생성**을 선택합니다.

1. 다음 설정을 구성합니다:
   + **함수 이름**: 함수의 이름을 입력합니다.
   + **런타임**: **Java 25**을 선택합니다.

1. **함수 생성**을 선택합니다.

콘솔은 `Hello`라는 핸들러 클래스를 사용하여 Lambda 함수를 만듭니다. 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)
+ [AWS Lambda에서 Java 코드 계측](java-tracing.md)
+ [AWS Lambda용 Java 샘플 애플리케이션](java-samples.md)

# Java에서 Lambda 함수 핸들러 정의
<a name="java-handler"></a>

Lambda 함수의 *핸들러*는 이벤트를 처리하는 함수 코드의 메서드입니다. 함수가 간접 호출되면 Lambda는 핸들러 메서드를 실행합니다. 함수는 핸들러가 응답을 반환하거나 종료하거나 제한 시간이 초과될 때까지 실행됩니다.

이 페이지에서는 프로젝트 설정, 이름 지정 규칙, 모범 사례를 포함하여 Java에서 Lambda 함수 핸들러를 사용하는 방법을 설명합니다. 이 페이지에는 주문에 대한 정보를 가져와서 텍스트 파일 영수증을 생성하고 해당 파일을 Amazon Simple Storage Service(Amazon S3) 버킷에 넣는 Java Lambda 함수의 예제도 포함되어 있습니다. 함수를 작성한 후 배포하는 방법에 대한 자세한 내용은 [.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)
+ [핸들러에서 AWS SDK for Java v2 사용](#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에서는 무엇이든 가능하지만 프로젝트의 디렉터리 구조와 일치해야 합니다. 여기서는 디렉터리 구조가 `src/main/java/example`이기 때문에 `package example`을 사용합니다.
+ `import` 문: Lambda 함수에 필요한 Java 클래스를 가져오는 데 사용합니다.
+ `public class OrderHandler ...`: Java 클래스를 정의하며 [유효한 클래스 정의](#java-handler-signatures)여야 합니다.
+ `private static final S3Client S3_CLIENT ...`: 클래스의 메서드 외부에서 S3 클라이언트를 초기화합니다. 이렇게 하면 [초기화 단계](lambda-runtime-environment.md#runtimes-lifecycle-ib)에서 Lambda가 이 코드를 실행합니다.
+ `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 버킷은 영수증 파일을 포함합니다.

**참고**  
이 함수를 제한 시간 없이 성공적으로 실행하려면 추가 구성 설정이 필요할 수 있습니다. 메모리는 256MB, 제한 시간은 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`.

`RequestHandler` 또는 `RequestStreamHandler` 인터페이스를 구현하지 않는 Java 내 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 레코드로 정의할 수 있습니다. 이 예제에서는 `Order` 객체를 나타내는 `OrderHandler` 클래스 내의 레코드를 정의합니다.

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

이 레코드는 예상 입력 형태와 일치합니다. 레코드를 정의한 후 레코드 정의를 준수하는 JSON 입력에 사용하는 핸들러 서명을 작성할 수 있습니다. Java 런타임은이 JSON을 Java 객체로 자동으로 역직렬화합니다. 그런 다음, 객체의 필드에 액세스할 수 있습니다. 예를 들어 `event.orderId`는 원래 입력에서 `orderId`의 값을 검색합니다.

**참고**  
Java 레코드는 Java 17 런타임 이상에 포함된 기능입니다. 모든 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) 섹션을 참조하세요.

## 핸들러에서 AWS SDK for Java v2 사용
<a name="java-example-sdk-usage"></a>

종종 Lambda 함수를 사용하여 다른 AWS 리소스와 상호 작용하거나 업데이트하는 경우가 있습니다. 이러한 리소스와 인터페이스로 접속하는 가장 간단한 방법은 AWS SDK for Java v2를 사용하는 것입니다.

**참고**  
AWS SDK for Java(v1)는 유지 관리 모드이며 2025년 12월 31일에 지원이 종료됩니다. 앞으로는 AWS SDK for Java v2만 사용하는 것을 권장합니다.

함수에 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) 시작 시 빠르게 로드되는 더 단순한 프레임워크가 권장됩니다. 예를 들어 [Spring Framework](https://github.com/spring-projects/spring-framework)와 같은 더 복잡한 프레임워크보다는 [Dagger](https://google.github.io/dagger/) 또는 [Guice](https://github.com/google/guice) 같은 더 단순한 Java 종속성 주입(IoC) 프레임워크를 선호합니다.
+ **배포 패키지 크기를 런타임 필요에 따라 최소화합니다.** 이렇게 하면 호출 전에 배포 패키지를 다운로드하고 압축을 풀 때 걸리는 시간이 단축됩니다. Java에서 작성된 함수의 경우, 배포 패키지의 일부로 전체 AWS SDK 라이브러리를 업로드하지 마세요. 대신, 필요한 SDK의 구성 요소를 선택하는 모듈을 선택적으로 활용합니다(예: DynamoDB, Amazon S3 SDK 모듈, [Lambda 핵심 라이브러리](https://github.com/aws/aws-lambda-java-libs)).

**실행 환경 재사용을 활용하여 함수 성능을 향상시킵니다.** 함수 핸들러 외부에서 SDK 클라이언트 및 데이터베이스 연결을 초기화하고 정적 자산을 `/tmp` 디렉토리에 로컬로 캐시합니다. 동일한 함수 인스턴스에서 처리하는 후속 간접 호출은 이러한 리소스를 재사용할 수 있습니다. 이를 통해 함수 실행 시간을 줄여 비용을 절감합니다.

호출에서 발생할 수 있는 데이터 유출을 방지하려면 실행 환경을 사용하여 사용자 데이터, 이벤트 또는 보안과 관련된 기타 정보를 저장하지 마세요. 함수가 핸들러 내부 메모리에 저장할 수 없는 변경 가능한 상태에 의존하는 경우 각 사용자에 대해 별도의 함수 또는 별도의 함수 버전을 생성하는 것이 좋습니다.

**연결 유지 지시문을 사용하여 지속적인 연결을 유지하세요.** Lambda는 시간이 지남에 따라 유휴 연결을 제거합니다. 함수를 호출할 때 유휴 연결을 재사용하려고 하면 연결 오류가 발생합니다. 지속적인 연결을 유지하려면 런타임과 관련된 연결 유지 지시문을 사용하세요. 예를 들어, [Node.js에서 연결 유지를 이용해 연결 재사용](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의 목록은 [API 레퍼런스](https://docs.aws.amazon.com/lambda/latest/api/welcome.html)를 참조하세요.

**멱등성 코드를 작성합니다.** 함수에 멱등성 코드를 작성하면 중복 이벤트가 동일한 방식으로 처리됩니다. 코드는 이벤트를 올바르게 검증하고 중복 이벤트를 정상적으로 처리해야 합니다. 자세한 내용은 [멱등성 Lambda 함수를 만들려면 어떻게 해야 합니까?](https://aws.amazon.com/premiumsupport/knowledge-center/lambda-function-idempotent/) 단원을 참조하십시오.
+ **Java DNS 캐시를 사용하지 마십시오.** Lambda 함수는 이미 DNS 응답을 캐싱하고 있습니다. 다른 DNS 캐시를 사용하는 경우 연결 시간 초과가 발생할 수 있습니다.

  `java.util.logging.Logger` 클래스는 JVM DNS 캐시를 간접적으로 활성화할 수 있습니다. 기본 설정을 재정의하려면 `logger` 초기화 전에 [networkaddress.cache.ttl](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/net/InetAddress.html#inetaddress-caching-heading)을 0으로 설정하십시오. 예시

  ```
  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 디렉터리에 배치하여 Java에서 생성된 **배포 패키지의 압축을 푸는 데 Lambda가 소요하는 시간을 단축합니다**. 이는 많은 수의 `.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) 캐시에 대한 지원이 도입되었습니다. Lambda가 관리형 런타임을 업데이트할 때 캐시가 예기치 않은 동작을 일으킬 수 있으므로 함수를 .zip 또는 JAR 파일 아카이브로 배포할 때 AOT 캐시를 사용하지 않는 것이 좋습니다. 자세한 내용은 [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은(는) 명령줄 셸의 명령을 사용하여 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) – 현재 호출의 요청 ID를 [함수 로그](java-logging.md)에 추가하는 데 사용할 수 있는 Apache Log4j 2용 appender 라이브러리입니다.
+ [AWS SDK for Java 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는 JAR 파일을 유니코드 알파벳순으로 로드합니다. `lib` 디렉터리의 여러 JAR 파일에 동일한 클래스가 있을 경우 첫 번째 클래스가 사용됩니다. 다음 셸 스크립트를 사용하여 중복 클래스를 식별할 수 있습니다.

**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)로 작업하는 경우 배포 패키지를 Lambda에 업로드하기 전에 `lib` 디렉터리에 MRJAR(즉, Maven Shade 플러그인에서 생성된 음영 처리된 JAR)을 포함하고 압축해야 합니다. 그렇지 않으면 Lambda가 JAR 파일의 압축을 제대로 풀지 못해 `MANIFEST.MF` 파일이 무시될 수 있습니다.

appender 라이브러리(`aws-lambda-java-log4j2`)를 사용하는 경우 Maven Shade 플러그인에 대한 변환기도 구성해야 합니다. 변환기 라이브러리는 appender 라이브러리와 Log4j에 모두 나타나는 캐시 파일 버전을 결합합니다.

**Example pom.xml – Log4j 2 appender를 사용하여 플러그인 구성**  

```
      <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 파일을 추가합니다.

 배포 패키지 파일이 50MB 미만인 경우 로컬 컴퓨터에서 직접 파일을 업로드하여 함수를 생성하거나 업데이트할 수 있습니다. 50MB보다 큰 .zip 또는 JAR 파일의 경우 먼저 패키지를 Amazon S3 버킷에 업로드해야 합니다. AWS Management Console을 사용하여 Amazon S3 버킷에 파일을 업로드하는 방법에 대한 지침은 [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. **새로 작성**을 선택합니다.

1. **기본 정보**에서 다음과 같이 합니다.

   1. **함수 이름**에 함수 이름을 입력합니다.

   1. **런타임**에서 사용할 런타임을 선택합니다.

   1. (선택 사항) **아키텍처**에서 함수에 대한 명령 세트 아키텍처를 선택합니다. 기본 아키텍처는 x86\$164입니다. 함수에 대한 .zip 배포 패키지가 선택한 명령 세트 아키텍처와 호환되는지 확인합니다.

1. (선택 사항) **권한(Permissions)**에서 **기본 실행 역할 변경(Change default execution role)**을 확장합니다. 새로운 **실행 역할**을 생성하거나 기존 실행 역할을 사용할 수 있습니다.

1. **함수 생성**을 선택합니다. 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 패키지를 배포합니다. 파일이 50MB보다 작은 경우 로컬 빌드 시스템의 파일 위치에서 패키지를 업로드할 수 있습니다. 더 큰 파일의 경우 Amazon S3 버킷에서 .zip 또는 JAR 패키지를 업로드해야 합니다. AWS CLI를 사용하여 Amazon S3 버킷에 파일을 업로드하는 방법에 대한 지침은 **AWS CLI 사용 설명서의 [객체 이동](https://docs.aws.amazon.com/cli/latest/userguide/cli-services-s3-commands.html#using-s3-commands-managing-objects-move)을 참조하세요.

**참고**  
AWS CLI를 사용하여 Amazon S3 버킷에서 .zip 또는 JAR 파일을 업로드하는 경우 버킷은 함수와 동일한 AWS 리전에 있어야 합니다.

 AWS CLI에서 .zip 또는 JAR 파일을 사용하여 새 함수를 생성하려면 다음을 지정해야 합니다.
+ 함수의 이름(`--function-name`)
+ 함수의 런타임(`--runtime`)
+ 함수의 [실행 역할](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html)(`--role`)의 Amazon 리소스 이름(ARN)
+ 함수 코드에 있는 핸들러 메서드의 이름(`--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) – Lambda를 사용하여 주문을 처리하는 방법을 보여주는 Java 함수입니다. 이 함수는 사용자 지정 입력 이벤트 객체를 정의 및 역직렬화하고 AWS SDK를 사용하며 로깅을 출력하는 방법을 보여줍니다.
+ [java-basic](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-basic) – 단위 테스트 및 변수 로깅 구성을 사용하는 최소한의 Java 함수 모음입니다.
+ [java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-events) - Amazon API Gateway, Amazon SQS 및 Amazon Kinesis와 같은 다양한 서비스의 이벤트를 처리하는 방법에 대한 스켈레톤 코드가 포함된 Java 함수 모음입니다. 이러한 함수는 최신 버전의 [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) – Amazon S3의 알림 이벤트를 처리하고 JCL(Java Class Library)을 사용하여 업로드된 이미지 파일의 썸네일을 생성하는 Java 함수입니다.
+ [layer-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/layer-java) - Lambda 계층을 사용하여 코어 함수 코드와 별도로 종속성을 패키징하는 방법을 보여주는 Java 함수입니다.

# 컨테이너 이미지로 Java Lambda 함수 배포
<a name="java-image"></a>

Java Lambda 함수의 컨테이너 이미지를 빌드하는 세 가지 방법이 있습니다.
+ [Java용 AWS 기본 이미지 사용](#java-image-instructions)

  [AWS 기본 이미지](images-create.md#runtimes-images-lp)에는 언어 런타임, Lambda와 함수 코드 간의 상호 작용을 관리하는 런타임 인터페이스 클라이언트 및 로컬 테스트를 위한 런타임 인터페이스 에뮬레이터가 미리 로드되어 있습니다.
+ [AWS OS 전용 기본 이미지 사용](images-create.md#runtimes-images-provided)

  [AWS OS 전용 기본 이미지](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)의 컨테이너 이미지를 생성하는 데 사용됩니다. OS 전용 기본 이미지를 사용하여 [사용자 지정 런타임](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/)을 참조하세요. 효율적인 컨테이너 이미지를 빌드하려면 [Dockerfile 작성 모범 사례](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)를 따르세요.

이 페이지에서는 Lambda용 컨테이너 이미지를 빌드, 테스트 및 배포하는 방법을 설명합니다.

**Topics**
+ [Java용 AWS 기본 이미지](#java-image-base)
+ [Java용 AWS 기본 이미지 사용](#java-image-instructions)
+ [런타임 인터페이스 클라이언트에서 대체 기본 이미지 사용](#java-image-clients)

## Java용 AWS 기본 이미지
<a name="java-image-base"></a>

AWS는 Java에 대한 다음과 같은 기본 이미지를 제공합니다.


| 태그 | 런타임 | 운영 체제 | 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 | [GitHub의 Java 21용 Dockerfile](https://github.com/aws/aws-lambda-base-images/blob/java21/Dockerfile.java21) |   2029년 6월 30일   | 
| 17 | Java 17 | Amazon Linux 2 | [GitHub의 Java 17용 Dockerfile](https://github.com/aws/aws-lambda-base-images/blob/java17/Dockerfile.java17) |   2027년 6월 30일   | 
| 11 | Java 11 | Amazon Linux 2 | [GitHub의 Java 11용 Dockerfile](https://github.com/aws/aws-lambda-base-images/blob/java11/Dockerfile.java11) |   2027년 6월 30일   | 
| 8.al2 | Java 8 | Amazon Linux 2 | [GitHub의 Java 8용 Dockerfile](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를 사용합니다. AL2023은 작은 배포 공간과 `glibc`와 같이 업데이트된 라이브러리 버전을 포함하여 Amazon Linux 2에 비해 여러 가지 이점을 제공합니다.

AL2023 기반 이미지는 `microdnf`(`dnf` 심볼릭 링크)를 Amazon Linux 2에서 기본 패키지 관리자인 `yum` 대신 패키지 관리자로 사용합니다. `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/)를 참조하세요.

**참고**  
AWS Serverless Application Model(AWS SAM)을 포함하여 AL2023 기반 이미지를 로컬에서 실행하려면 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)를 참조하세요.
   + **리전** – 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로 컴파일되도록 미리 구성되어 있으며 AWS SDK for Java에 대한 종속 구성 요소를 포함합니다. 다른 아키타이프 또는 다른 메서드를 사용하여 프로젝트를 생성하는 경우 [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 사용자를 자동으로 정의합니다. 이는 `USER` 지침이 제공되지 않을 때 `root` 사용자에게 기본 설정이 적용되는 표준 Docker 동작과는 다릅니다.  
**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-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 .
   ```
**참고**  
이 명령은 빌드 머신의 아키텍처에 관계없이 컨테이너가 Lambda 실행 환경과 호환되는지 확인하기 위해 `--platform linux/amd64` 옵션을 지정합니다. 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 정의 환경 변수](configuration-envvars.md#configuration-envvars-runtime)인 `{LAMBDA_TASK_ROOT}`에 복사합니다.
   + `CMD` 인수를 Lambda 함수 핸들러로 설정합니다.

   참고로 Dockerfile 예제에는 [USER 지침](https://docs.docker.com/reference/dockerfile/#user)이 포함되어 있지 않습니다. Lambda에 컨테이너 이미지를 배포할 때 Lambda는 권한이 최소 권한인 기본 Linux 사용자를 자동으로 정의합니다. 이는 `USER` 지침이 제공되지 않을 때 `root` 사용자에게 기본 설정이 적용되는 표준 Docker 동작과는 다릅니다.  
**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-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 .
   ```
**참고**  
이 명령은 빌드 머신의 아키텍처에 관계없이 컨테이너가 Lambda 실행 환경과 호환되는지 확인하기 위해 `--platform linux/amd64` 옵션을 지정합니다. 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 명령 세트 아키텍처를 위한 도커 이미지를 빌드한 경우 `--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` 값을 Amazon ECR 리포지토리를 생성하려는 AWS 리전으로 설정합니다.
   + `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 리소스 이름(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 함수에 배포하려면 Amazon ECR의 이미지 태그가 동일하게 유지되더라도 [update-function-code](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-code.html) 명령을 사용해야 합니다. 다음 예제에서 `--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>

[OS 전용 기본 이미지](images-create.md#runtimes-images-provided)나 대체 기본 이미지를 사용하는 경우 이미지에 런타임 인터페이스 클라이언트를 포함해야 합니다. 런타임 인터페이스 클라이언트는 Lambda와 함수 코드 간의 상호 작용을 관리하는 [런타임 API](runtimes-api.md)을 확장합니다.

Java용 런타임 인터페이스 클라이언트를 Docker 파일에 설치하거나 프로젝트의 종속 항목으로 설치합니다. 예를 들어, 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로 설정합니다.
   + Docker 컨테이너가 시작될 때 실행할 모듈로 `ENTRYPOINT`를 설정합니다. 이 경우 모듈은 런타임 인터페이스 클라이언트입니다.
   + `CMD` 인수를 Lambda 함수 핸들러로 설정합니다.

   참고로 Dockerfile 예제에는 [USER 지침](https://docs.docker.com/reference/dockerfile/#user)이 포함되어 있지 않습니다. Lambda에 컨테이너 이미지를 배포할 때 Lambda는 권한이 최소 권한인 기본 Linux 사용자를 자동으로 정의합니다. 이는 `USER` 지침이 제공되지 않을 때 `root` 사용자에게 기본 설정이 적용되는 표준 Docker 동작과는 다릅니다.  
**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-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 .
   ```
**참고**  
이 명령은 빌드 머신의 아키텍처에 관계없이 컨테이너가 Lambda 실행 환경과 호환되는지 확인하기 위해 `--platform linux/amd64` 옵션을 지정합니다. 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`는 Docker 파일의 `CMD` 다음에 오는 `ENTRYPOINT`입니다.

------
#### [ 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 명령 세트 아키텍처를 위한 도커 이미지를 빌드한 경우 `--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` 값을 Amazon ECR 리포지토리를 생성하려는 AWS 리전으로 설정합니다.
   + `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 리소스 이름(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 함수에 배포하려면 Amazon ECR의 이미지 태그가 동일하게 유지되더라도 [update-function-code](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-code.html) 명령을 사용해야 합니다. 다음 예제에서 `--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>` 섹션에서는 종속성을 단일 uber-jar로 번들링하는 대신 [maven-dependency-plugin](https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-dependency-plugin)을 사용하여 각 종속성에 대해 별도의 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. `java/lib` 디렉터리에 종속성 JAR 파일을 복사합니다.

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

1. 계층 콘텐츠를 .zip 파일로 압축합니다.

------
#### [ 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
   ```
**참고**  
파일의 루트 수준에 `java` 디렉터리가 포함되어 있고 그 안에 `lib`가 있는지 확인하세요. 이 구조는 Lambda가 라이브러리를 찾아서 가져올 수 있도록 합니다. 각 종속성은 uber-jar로 번들링되지 않고 별도의 JAR 파일로 유지됩니다.

## Lambda에서 계층 생성
<a name="publishing-layer"></a>

AWS CLI 또는 Lambda 콘솔을 사용하여 계층을 게시할 수 있습니다.

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

[publish-layer-version](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/publish-layer-version.html) AWS CLI 명령을 실행하여 Lambda 계층을 생성합니다.

```
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. **생성(Create)**을 선택합니다.

------

## 함수에 계층 추가
<a name="java-layer-adding"></a>

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

함수에 계층을 연결하려면 [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"
```

**cli-binary-format** 옵션은 AWS CLI 버전 2를 사용할 때 필요합니다. 이 설정을 기본 설정으로 지정하려면 `aws configure set cli-binary-format raw-in-base64-out`을(를) 실행하세요. 자세한 내용은 [AWS CLI 지원되는 글로벌 명령줄 옵션](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)을 *AWS Command Line Interface 사용 설명서 버전 2에서 참조하세요*.

------
#### [ 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) 라이브러리를 종속성으로 추가합니다. 이 라이브러리에는 Lambda에서 Java로 작업하기 위한 다른 인터페이스 정의와 함께 [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) 인터페이스가 포함되어 있습니다.

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 리포지토리에 있는 [사용자 지정 직렬화](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 간접 호출](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 간접 호출 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>

이 페이지에서는 AWS Lambda의 Java 함수와 관련된 설정을 설명합니다. 이러한 설정을 사용하여 Java 런타임 시작 동작을 사용자 지정할 수 있습니다. 이를 통해 코드를 수정하지 않고도 전체 함수 지연 시간을 줄이고 전체 함수 성능을 개선할 수 있습니다.

**Topics**
+ [`JAVA_TOOL_OPTIONS` 환경 변수에 대한 이해](#java-tool-options)
+ [Log4Shell용 Log4j 패치](#log4shell-patch)
+ [Ahead-of-Time(AOT) 및 CDS 캐시](#aot-cds-caches)

## `JAVA_TOOL_OPTIONS` 환경 변수에 대한 이해
<a name="java-tool-options"></a>

Java에서 Lambda는 Lambda에서 추가 명령줄 변수를 설정할 수 있도록 `JAVA_TOOL_OPTIONS` 환경 변수를 지원합니다. 계층형 컴파일 설정을 사용자 지정하는 등 다양한 방식으로 이 환경 변수를 사용할 수 있습니다. 다음 예제에서는 이 사용 사례에 `JAVA_TOOL_OPTIONS` 환경 변수를 사용하는 방법을 설명합니다.

### 예제: 계층형 컴파일 설정에 대한 사용자 지정
<a name="tiered-compilation"></a>

계층형 컴파일은 Java 가상 머신(JVM)의 기능입니다. 특정 계층형 컴파일 설정을 사용하여 JVM의 JIT(Just-In-Time) 컴파일러를 최대한 활용할 수 있습니다. 일반적으로 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는 기본적으로 레벨 1에서 계층형 컴파일을 중지하도록 JVM을 구성합니다. Java 25에서 Lambda는 기본 JVM 설정이 사용되는 SnapStart 또는 프로비저닝 동시성을 사용하는 경우를 제외하고 기본적으로 레벨 1에서 계층형 컴파일을 계속 중지합니다. 이를 통해 계층형 컴파일이 간접 호출 경로 외부에서 수행되므로 콜드 스타트 페널티가 발생하지 않고 SnapStart 및 프로비저닝 동시성의 성능이 개선됩니다. 이 이점을 극대화하기 위해 SnapStart 스냅샷을 생성하기 전에 또는 프로비저닝 동시성 실행 환경이 사전 프로비저닝될 때 함수 초기화 중에 코드 경로를 실행하여 JIT를 트리거하는 준비 작업을 사용할 수 있습니다. 자세한 내용은 블로그 게시물 [Optimizing cold start performance of AWS Lambda using advanced priming strategies with SnapStart](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/ko_kr/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 런타임도 직렬 GC를 사용합니다. 그러나 Java 17에서는 `JAVA_TOOL_OPTIONS` 환경 변수를 사용하여 기본 GC를 변경할 수도 있습니다. 병렬 GC와 [Shenandoah GC](https://wiki.openjdk.org/display/shenandoah/Main) 중에서 선택할 수 있습니다.

예를 들어 워크로드에 더 많은 메모리와 여러 CPU를 사용하는 경우 병렬 GC를 사용하여 성능을 향상시킬 수 있습니다. `JAVA_TOOL_OPTIONS` 환경 변수 값에 다음을 추가하여 이 작업을 수행할 수 있습니다.

```
-XX:+UseParallelGC
```

워크로드에 수명이 짧은 객체가 많은 경우 Java 25에 도입된 Shenandoah 가비지 수집기의 세대 모드를 활성화하여 메모리 소비량을 줄일 수 있습니다. 이를 위해 `JAVA_TOOL_OPTIONS` 환경 변수 값에 다음을 추가합니다.

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

## Log4Shell용 Log4j 패치
<a name="log4shell-patch"></a>

Java 8, 11, 17 및 21용 Lambda 런타임에는 자주 사용되는 Java 로깅 프레임워크인 Log4j에서 Log4Shell 취약성(CVE-2021-44228)을 완화하는 패치가 포함되어 있습니다. 이 패치를 통해 콜드 스타트 성능 오버헤드가 발생합니다. 패치된 버전의 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 런타임에는 Lambda 런타임 API의 이벤트를 적극적으로 폴링하는 런타임 구성 요소인 Java 런타임 인터페이스 클라이언트(RIC)에 대한 Ahead-of-Time(AOT) 캐시가 포함되어 있습니다. 이를 통해 콜드 스타트 성능이 개선됩니다.

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 리소스 이름(ARN)을 반환합니다. 간접 호출자가 버전 번호 또는 별칭을 지정했는지 여부를 나타냅니다.
+ `getMemoryLimitInMB()` – 함수에 할당된 메모리의 양을 반환합니다.
+ `getAwsRequestId()` – 호출 요청의 식별자를 반환합니다.
+ `getLogGroupName()` – 함수에 대한 로그 그룹을 반환합니다.
+ `getLogStreamName()` – 함수 인스턴스에 대한 로그 스트림을 반환합니다.
+ `getIdentity()` – (모바일 앱) 요청을 승인한 Amazon Cognito 자격 증명에 대한 정보를 반환합니다.
+ `getClientContext()` – (모바일 앱) 클라이언트 애플리케이션이 Lambda에게 제공한 클라이언트 컨텍스트를 반환합니다.
+ `getLogger()` – 함수에 대한 [로거 객체](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) – Lambda를 사용하여 주문을 처리하는 방법을 보여주는 Java 함수입니다. 이 함수는 사용자 지정 입력 이벤트 객체를 정의 및 역직렬화하고 AWS SDK를 사용하며 로깅을 출력하는 방법을 보여줍니다.
+ [java-basic](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-basic) – 단위 테스트 및 변수 로깅 구성을 사용하는 최소한의 Java 함수 모음입니다.
+ [java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-events) - Amazon API Gateway, Amazon SQS 및 Amazon Kinesis와 같은 다양한 서비스의 이벤트를 처리하는 방법에 대한 스켈레톤 코드가 포함된 Java 함수 모음입니다. 이러한 함수는 최신 버전의 [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) – Amazon S3의 알림 이벤트를 처리하고 JCL(Java Class Library)을 사용하여 업로드된 이미지 파일의 썸네일을 생성하는 Java 함수입니다.
+ [layer-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/layer-java) - Lambda 계층을 사용하여 코어 함수 코드와 별도로 종속성을 패키징하는 방법을 보여주는 Java 함수입니다.

# Java Lambda 함수 로깅 및 모니터링
<a name="java-logging"></a>

AWS Lambda는 자동으로 Lambda 함수를 모니터링하고 로그 항목을 Amazon CloudWatch로 보냅니다. Lambda 함수는 함수의 각 인스턴스에 대한 CloudWatch Logs 로그 그룹 및 로그 스트림과 함께 제공됩니다. Lambda 런타임 환경은 각 간접 호출에 대한 세부 정보와 함수 코드의 기타 출력을 로그 스트림으로 전송합니다. CloudWatch Logs에 대한 자세한 내용은 [CloudWatch Logs로 Lambda 함수 로그 전송](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입니다.
+ **샘플링 완료(Sampled)** – 추적된 요청의 경우 샘플링 결과입니다.

## 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는 `LambdaLogger` 클래스를 사용하여 로그 출력을 구조화된 JSON으로 전송합니다. 각 JSON 로그 객체에는 다음 키가 있는 4개의 키 값 페어가 포함되어 있습니다.
+ `"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 구조화된 로그를 코드에 만들 수 있습니다. `stdout` 또는 `stderr`에 JSON 로그를 쓸 수 있는 로깅 라이브러리를 사용할 수 있습니다. 예를 들어 AWS Lambda용 Powertools 또는 Log4j2 패키지를 사용하여 코드로부터 JSON 구조화된 로그 출력을 생성할 수 있습니다. 자세한 내용은 [구조화된 로깅에 Powertools for AWS Lambda(Java) 및 AWS SAM 사용](#java-logging-sam) 및 [Log4j2 및 SLF4J를 사용한 고급 로깅 구현](#java-logging-log4j2)를 참조하세요.

로그 수준 필터링을 사용하도록 함수를 구성할 때는 Lambda가 CloudWatch 로그로 전송하기를 원하는 로그 수준을 다음 옵션 중에서 선택해야 합니다.


| 로그 수준 | 표준 사용량 | 
| --- | --- | 
| TRACE(최대 세부 정보) | 코드 실행 경로를 추적하는 데 사용되는 가장 세밀한 정보 | 
| DEBUG | 시스템 디버깅에 대한 세부 정보 | 
| INFO | 함수의 정상 작동을 기록하는 메시지 | 
| WARN | 해결되지 않을 경우 예상치 못한 동작으로 이어질 수 있는 잠재적 오류에 대한 메시지 | 
| 오류 | 코드가 예상대로 작동하지 못하게 하는 문제에 대한 메시지 | 
| 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 버전전을 포함하는 경우, CVE-2021-44228, CVE-2021-45046 및 CVE-2021-45105의 문제를 완화하는 데 도움이 되는 Lambda Java [관리형 런타임](lambda-runtimes.md)과[기본 컨테이너 이미지](java-image.md)에 변경 사항을 적용했습니다. 이 변경의 결과로 Log4J2를 사용하는 고객은 '`Transforming org/apache/logging/log4j/core/lookup/JndiLookup (java.net.URLClassLoader@...)`'과 유사한 추가 로그 입력 항목을 볼 수 있습니다. Log4J2 출력에서 jndi 매퍼를 참조하는 모든 로그 문자열은 '`Patched JndiLookup::lookup()`으로 대체됩니다.  
 이러한 변경과 관계없이 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 또는 1.0.1)**와 관련된 모든 라이브러리는 **절대** **어떤** 상황에서도 사용해서는 안 된다는 점에 유의합니다. 이러한 라이브러리는 2015년에 수명이 끝난 log4j의 버전 1.x와(과) 관련이 있습니다. 라이브러리가 지원되지 않고, 유지 관리되지 않으며, 패치가 적용되지 않으며, 알려져 있는 보안 취약성이 있습니다.

로그 출력을 사용자 지정하고, 단위 테스트 중 로깅을 지원하고, AWS SDK 호출을 기록하려면 Apache Log4j2를 SLF4J와 함께 사용합니다. Log4j는 Java 프로그램을 위한 로깅 라이브러리로서, 로그 수준을 구성하고 appender 라이브러리를 사용할 수 있도록 합니다. SLF4J는 facade 라이브러리로서, 함수 코드를 변경하지 않고 사용하는 라이브러리를 변경할 수 있도록 합니다.

함수의 로그에 요청 ID를 추가하려면 [aws-lambda-java-log4j2](java-package.md) 라이브러리의 appender를 사용합니다.

**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) – Appender 구성**  

```
<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 코드에 로깅하기 위한 facade 라이브러리입니다. 함수 코드에서 SLF4J 로거 팩토리를 사용하여 `info()` 및 `warn()`과 같은 로그 수준에 대한 메서드로 로거를 가져옵니다. 빌드 구성에서 로깅 라이브러리와 SLF4J 어댑터를 클래스 경로에 포함합니다. 빌드 구성에서 라이브러리를 변경하면 함수 코드를 변경하지 않고 로거 유형을 변경할 수 있습니다. 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 appender 및 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 appender가 사용할 요청 ID가 없습니다. 테스트 구성에 대한 예는 다음 단원의 샘플 애플리케이션을 참조하세요.

## 기타 로깅 도구 및 라이브러리 사용
<a name="java-tools-libraries"></a>

[Powertools for AWS Lambda(Java)](https://docs.aws.amazon.com/powertools/java/)는 서버리스 모범 사례를 구현하고 개발자 속도를 높이기 위한 개발자 도구 키트입니다. [Logging 유틸리티](https://docs.aws.amazon.com/powertools/java/latest/core/logging/)는 JSON으로 구조화된 출력과 함께 모든 함수의 함수 컨텍스트에 대한 추가 정보를 포함하는 Lambda 최적화 로거를 제공합니다. 이 유틸리티를 사용하여 다음을 수행합니다.
+ Lambda 컨텍스트, 콜드 스타트 및 구조 로깅 출력에서 JSON으로 주요 필드 캡처
+ 지시 시 Lambda 호출 이벤트 로깅(기본적으로 비활성화됨)
+ 로그 샘플링을 통해 호출 비율에 대해서만 모든 로그 인쇄(기본적으로 비활성화됨)
+ 언제든지 구조화된 로그에 추가 키 추가
+ 사용자 지정 로그 포맷터(Bring Your Own Formatter)를 사용하여 조직의 로깅 RFC와 호환되는 구조로 로그 출력

## 구조화된 로깅에 Powertools for AWS Lambda(Java) 및 AWS SAM 사용
<a name="java-logging-sam"></a>

다음 단계를 따라 AWS SAM를 사용하는 통합 [Powertools for AWS Lambda(Java)](https://docs.aws.amazon.com/powertools/java/latest/) 모듈을 사용하여 샘플 Hello World Java 애플리케이션을 다운로드, 빌드 및 배포합니다. 이 애플리케이션은 기본 API 백엔드를 구현하고 Powertools를 사용하여 로그, 지표 및 추적을 내보냅니다. 이 구성에는 Amazon API Gateway 엔드포인트와 Lambda 함수가 포함됩니다. API Gateway 엔드포인트로 GET 요청을 전송하면 Lambda 함수가 간접 호출되고 Embedded Metric Format을 사용하여 로그 및 지표를 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에 권한 부여가 정의되어 있지 않을 수 있습니다. 괜찮습니다?**에 대해 `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 logs](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은(는) 명령줄 셸의 명령을 사용하여 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` 명령 옵션을 통해 호출에 대한 로그를 검색할 수 있습니다. 호출에서 base64로 인코딩된 로그를 최대 4KB까지 포함하는 `LogResult` 필드가 응답에 포함됩니다.

**Example 로그 ID 검색**  
다음 예제에서는 `LogResult`이라는 함수의 `my-function` 필드에서 *로그 ID*를 검색하는 방법을 보여줍니다.  

```
aws lambda invoke --function-name my-function out --log-type Tail
```
다음 결과가 표시됩니다:  

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

**Example decode the logs**  
동일한 명령 프롬프트에서 `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
```
**cli-binary-format** 옵션은 AWS CLI 버전 2를 사용할 때 필요합니다. 이 설정을 기본 설정으로 지정하려면 `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 스크립트**  
동일한 명령 프롬프트에서 다음 스크립트를 사용하여 마지막 5개 로그 이벤트를 다운로드합니다. 이 스크립트는 `sed`를 사용하여 출력 파일에서 따옴표를 제거하고, 로그를 사용할 수 있는 시간을 허용하기 위해 15초 동안 대기합니다. 출력에는 Lambda의 응답과 `get-log-events` 명령의 출력이 포함됩니다.  
다음 코드 샘플의 내용을 복사하고 Lambda 프로젝트 디렉터리에 `get-logs.sh`로 저장합니다.  
**cli-binary-format** 옵션은 AWS CLI 버전 2를 사용할 때 필요합니다. 이 설정을 기본 설정으로 지정하려면 `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 마지막 5개 로그 이벤트 검색**  
동일한 명령 프롬프트에서 다음 스크립트를 실행하여 마지막 5개 로그 이벤트를 가져옵니다.  

```
./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) – Lambda를 사용하여 주문을 처리하는 방법을 보여주는 Java 함수입니다. 이 함수는 사용자 지정 입력 이벤트 객체를 정의 및 역직렬화하고 AWS SDK를 사용하며 로깅을 출력하는 방법을 보여줍니다.
+ [java-basic](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-basic) – 단위 테스트 및 변수 로깅 구성을 사용하는 최소한의 Java 함수 모음입니다.
+ [java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-events) - Amazon API Gateway, Amazon SQS 및 Amazon Kinesis와 같은 다양한 서비스의 이벤트를 처리하는 방법에 대한 스켈레톤 코드가 포함된 Java 함수 모음입니다. 이러한 함수는 최신 버전의 [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) – Amazon S3의 알림 이벤트를 처리하고 JCL(Java Class Library)을 사용하여 업로드된 이미지 파일의 썸네일을 생성하는 Java 함수입니다.
+ [layer-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/layer-java) - Lambda 계층을 사용하여 코어 함수 코드와 별도로 종속성을 패키징하는 방법을 보여주는 Java 함수입니다.

`java-basic` 샘플 애플리케이션은 로깅 테스트를 지원하는 최소 로깅 구성을 보여 줍니다. 핸들러 코드는 컨텍스트 객체가 제공하는 `LambdaLogger` 로거를 사용합니다. 애플리케이션은 테스트를 위해 Log4j2 로거와 함께 `TestLogger` 인터페이스를 구현하는 사용자 지정 `LambdaLogger` 클래스를 사용합니다. AWS SDK와의 호환성을 위한 facade로 SLF4J를 사용합니다. 로깅 라이브러리는 배포 패키지를 작게 유지하기 위해 빌드 출력에서 제외되어 있습니다.

# AWS Lambda에서 Java 코드 계측
<a name="java-tracing"></a>

Lambda는 AWS X-Ray와 통합되어 Lambda 애플리케이션을 추적, 디버깅 및 최적화할 수 있습니다. Lambda 함수와 기타 AWS 서비스를 포함할 수 있는 애플리케이션의 리소스를 탐색할 때 X-Ray를 사용하여 요청을 추적할 수 있습니다.

추적 데이터를 X-Ray로 전송하려면 다음 두 SDK 라이브러리 중 하나를 사용할 수 있습니다.
+ [AWS Distro for OpenTelemetry(ADOT)](https://aws.amazon.com/otel) - 안전하게 프로덕션 준비가 된 AWS에서 지원하는 OpenTelemetry(OTEL) SDK의 배포입니다.
+ [AWS X-Ray SDK for Java](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 for AWS Lambda SDK는 AWS에서 제공하는 긴밀하게 통합된 계측 솔루션의 일부입니다. ADOT Lambda Layer는 일반적으로 더 많은 데이터를 수집하는 추적 계측기에 대한 전체 업계 표준의 일부이지만 모든 사용 사례에 적합하지는 않을 수 있습니다. 어떤 솔루션을 사용하든 X-Ray에서 엔드 투 엔드 추적 기능을 구현할 수 있습니다. 둘 중 하나를 선택하는 방법에 대해 자세히 알아보려면 [AWS Distro for Open Telemetry와 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>

다음 단계를 따라 AWS SAM를 사용하는 통합 [Powertools for AWS Lambda(Java)](https://docs.powertools.aws.dev/lambda-java) 모듈을 사용하여 샘플 Hello World Java 애플리케이션을 다운로드, 빌드 및 배포합니다. 이 애플리케이션은 기본 API 백엔드를 구현하고 Powertools를 사용하여 로그, 지표 및 추적을 내보냅니다. 이 구성에는 Amazon API Gateway 엔드포인트와 Lambda 함수가 포함됩니다. API Gateway 엔드포인트로 GET 요청을 전송하면 Lambda 함수가 간접 호출되고 Embedded Metric Format을 사용하여 로그 및 지표를 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에 권한 부여가 정의되어 있지 않을 수 있습니다. 괜찮습니다?**에 대해 `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 traces](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>

다음 단계를 따라 AWS CDK를 사용하는 통합 [Powertools for AWS Lambda(Java)](https://docs.powertools.aws.dev/lambda-java) 모듈을 사용하여 샘플 Hello World Java 애플리케이션을 다운로드, 빌드 및 배포합니다. 이 애플리케이션은 기본 API 백엔드를 구현하고 Powertools를 사용하여 로그, 지표 및 추적을 내보냅니다. 이 구성에는 Amazon API Gateway 엔드포인트와 Lambda 함수가 포함됩니다. API Gateway 엔드포인트로 GET 요청을 전송하면 Lambda 함수가 간접 호출되고 Embedded Metric Format을 사용하여 로그 및 지표를 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 Constructor](https://docs.aws.amazon.com/cdk/api/v1/java/aws_cdk.aws_lambda.html)와 [ApiGatewayv2 Constructor](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 traces](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는 OTel SDK를 사용하여 원격 측정 데이터를 수집하는 데 필요한 모든 것을 패키징할 수 있는 완전 관리형 Lambda [계층](chapter-layers.md)을 제공합니다. 이 계층을 사용하면 모든 함수 코드를 수정하지 않고도 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 설명서의 [AWS Distro for OpenTelemetry Lambda Support for Java (Auto-instrumentation Agent)(Java용 Distro for OpenTelemetry Lambda Support(자동 계측 에이전트))](https://aws-otel.github.io/docs/getting-started/lambda/lambda-java-auto-instr)를 참조하세요.
+ **AWS ADOT Java용 관리형 Lambda 계층** - 이 계층은 Lambda 함수에 대한 기본 제공 계측도 제공하지만, OTel SDK를 초기화하려면 몇 가지 코드를 직접 변경해야 합니다. 이 계층을 사용하는 방법에 대한 자세한 지침은 ADOT 설명서의 [AWS Distro for OpenTelemetry Lambda Support for Java(Java용 Distro for OpenTelemetry Lambda Support)](https://aws-otel.github.io/docs/getting-started/lambda/lambda-java)를 참조하세요.

## X-Ray SDK를 사용하여 Java 함수 계측
<a name="java-xray-sdk"></a>

함수가 애플리케이션의 다른 리소스 및 서비스에 대해 수행하는 호출과 관련된 데이터를 기록하려면 Java용 X-Ray SDK를 빌드 구성에 추가합니다. 다음 예에서는 AWS SDK for Java 2.x 클라이언트의 자동 계측을 활성화하는 라이브러리를 포함하는 Gradle 빌드 구성을 보여줍니다.

**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. **구성(Configuration)**을 선택한 다음 **모니터링 및 운영 도구(Monitoring and operations tools)**를 선택합니다.

1. **추가 모니터링 도구**에서 **편집**을 선택합니다.

1. **CloudWatch 애플리케이션 신호 및 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)는 애플리케이션 및 모든 구성 요소에 대한 정보를 보여줍니다. 다음 예제에서는 2개의 함수가 있는 애플리케이션을 보여줍니다. 기본 함수는 이벤트를 처리하고 때로는 오류를 반환합니다. 맨 위의 두 번째 함수는 첫 번째의 로그 그룹에 나타나는 오류를 처리하고 AWS SDK를 사용하여 X-Ray, Amazon Simple Storage Service(Amazon S3), Amazon CloudWatch Logs를 호출합니다.

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


X-Ray는 애플리케이션에 대한 모든 요청을 추적하지 않습니다. X-Ray는 모든 요청의 대표 샘플을 여전히 제공하면서 추적이 효율적으로 수행되도록 샘플링 알고리즘을 적용합니다. 샘플링 요율은 초당 요청이 1개이며 추가 요청의 5퍼센트입니다. 함수에 대해 X-Ray 샘플링 요율을 구성할 수 없습니다.

X-Ray에서 *추적*은 하나 이상의 *서비스*에서 처리되는 요청에 대한 정보를 기록합니다. Lambda는 각 추적에 대해 2개의 세그먼트를 기록하고, 이에 따라 서비스 그래프에 2개의 노드가 생성됩니다. 다음 이미지에서는 이 두 노드를 강조 표시합니다.

![\[\]](http://docs.aws.amazon.com/ko_kr/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/ko_kr/lambda/latest/dg/images/V2_sandbox_images/my-function-2-v1.png)


이 예제에서는 3개의 하위 세그먼트를 표시하도록 `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 개발자 안내서*의 [AWS X-Ray SDK for Java](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 SDK를 사용하여 AWS SDK 클라이언트를 계측하는 경우 함수 코드와 배포 패키지가 상당히 커질 수 있습니다. 함수 코드를 업데이트할 때마다 런타임 종속성을 업로드하지 않으려면 X-Ray SDK를 [Lambda 계층](chapter-layers.md)에 패키징합니다.

다음 예에서는 AWS SDK for Java 및 Java용 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) – Lambda를 사용하여 주문을 처리하는 방법을 보여주는 Java 함수입니다. 이 함수는 사용자 지정 입력 이벤트 객체를 정의 및 역직렬화하고 AWS SDK를 사용하며 로깅을 출력하는 방법을 보여줍니다.
+ [java-basic](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-basic) – 단위 테스트 및 변수 로깅 구성을 사용하는 최소한의 Java 함수 모음입니다.
+ [java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-events) - Amazon API Gateway, Amazon SQS 및 Amazon Kinesis와 같은 다양한 서비스의 이벤트를 처리하는 방법에 대한 스켈레톤 코드가 포함된 Java 함수 모음입니다. 이러한 함수는 최신 버전의 [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) – Amazon S3의 알림 이벤트를 처리하고 JCL(Java Class Library)을 사용하여 업로드된 이미지 파일의 썸네일을 생성하는 Java 함수입니다.
+ [layer-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/layer-java) - Lambda 계층을 사용하여 코어 함수 코드와 별도로 종속성을 패키징하는 방법을 보여주는 Java 함수입니다.

모든 샘플 애플리케이션은 Lambda 함수에 대해 활성 추적을 사용하도록 설정되어 있습니다. `s3-java` 애플리케이션은 AWS SDK for Java 2.x 클라이언트의 자동 계측, 테스트를 위한 세그먼트 관리, 사용자 지정 하위 세그먼트 및 런타임 종속성을 저장하기 위한 Lambda 계층의 사용을 보여줍니다.

# AWS Lambda용 Java 샘플 애플리케이션
<a name="java-samples"></a>

이 안내서의 GitHub 리포지토리는 AWS Lambda에서 Java를 사용하는 방법을 보여주는 샘플 애플리케이션을 제공합니다. 각 샘플 애플리케이션에는 간편한 배포 및 정리를 위한 스크립트, CloudFormation 템플릿 및 지원 리소스가 포함되어 있습니다.

**Java의 샘플 Lambda 애플리케이션**
+ [example-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/example-java) – Lambda를 사용하여 주문을 처리하는 방법을 보여주는 Java 함수입니다. 이 함수는 사용자 지정 입력 이벤트 객체를 정의 및 역직렬화하고 AWS SDK를 사용하며 로깅을 출력하는 방법을 보여줍니다.
+ [java-basic](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-basic) – 단위 테스트 및 변수 로깅 구성을 사용하는 최소한의 Java 함수 모음입니다.
+ [java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/java-events) - Amazon API Gateway, Amazon SQS 및 Amazon Kinesis와 같은 다양한 서비스의 이벤트를 처리하는 방법에 대한 스켈레톤 코드가 포함된 Java 함수 모음입니다. 이러한 함수는 최신 버전의 [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) – Amazon S3의 알림 이벤트를 처리하고 JCL(Java Class Library)을 사용하여 업로드된 이미지 파일의 썸네일을 생성하는 Java 함수입니다.
+ [layer-java](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/layer-java) - Lambda 계층을 사용하여 코어 함수 코드와 별도로 종속성을 패키징하는 방법을 보여주는 Java 함수입니다.

**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 Cloud 함수](https://spring.io/projects/spring-cloud-function) 프레임워크를 사용하여 AWS Lambda 함수를 생성하는 방법을 보여주는 Spring 예제입니다.
+ [서버리스 Spring Boot 애플리케이션 데모](https://github.com/aws-samples/serverless-java-frameworks-samples/tree/main/springboot) - SnapStart를 사용하거나 사용하지 않는 관리형 Java 런타임에서 일반적인 Spring Boot 애플리케이션을 설정하거나 사용자 지정 런타임이 있는 GraalVM 네이티브 이미지로 설정하는 방법을 보여주는 예제입니다.
+ [서버리스 Micronaut 애플리케이션 데모](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)에서 자세히 알아보세요.
+ [서버리스 Quarkus 애플리케이션 데모](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의 사용을 보여줍니다. 이러한 예제에는 최소한의 설정이 필요하며 1분 이내에 명령줄에서 배포할 수 있습니다.