쿠키 기본 설정 선택

당사는 사이트와 서비스를 제공하는 데 필요한 필수 쿠키 및 유사한 도구를 사용합니다. 고객이 사이트를 어떻게 사용하는지 파악하고 개선할 수 있도록 성능 쿠키를 사용해 익명의 통계를 수집합니다. 필수 쿠키는 비활성화할 수 없지만 '사용자 지정' 또는 ‘거부’를 클릭하여 성능 쿠키를 거부할 수 있습니다.

사용자가 동의하는 경우 AWS와 승인된 제3자도 쿠키를 사용하여 유용한 사이트 기능을 제공하고, 사용자의 기본 설정을 기억하고, 관련 광고를 비롯한 관련 콘텐츠를 표시합니다. 필수가 아닌 모든 쿠키를 수락하거나 거부하려면 ‘수락’ 또는 ‘거부’를 클릭하세요. 더 자세한 내용을 선택하려면 ‘사용자 정의’를 클릭하세요.

AWS SDK for Java 2.x를 사용한 DynamoDB 프로그래밍

포커스 모드
AWS SDK for Java 2.x를 사용한 DynamoDB 프로그래밍 - Amazon DynamoDB

이 프로그래밍 안내서는 Java를 통해 Amazon DynamoDB를 사용하려는 프로그래머에게 지침을 제공합니다. 이 안내서는 추상화 계층, 구성 관리, 오류 처리, 재시도 정책 제어, 연결 유지 관리와 같은 다양한 개념을 다룹니다.

AWS SDK for Java 2.x 소개

공식 AWS SDK for Java를 사용하여 Java에서 DynamoDB에 액세스할 수 있습니다. SDK for Java에는 1.x와 2.x의 두 가지 버전이 있습니다. 1.x의 경우 2024년 1월 12일에 지원 종료가 발표되었습니다. 2024년 7월 31일에 유지 관리 모드로 전환될 계획이며, 2025년 12월 31일에 지원이 종료될 예정입니다. 새 개발의 경우 2018년에 처음 릴리스된 2.x를 사용하는 것이 좋습니다. 이 안내서는 2.x만을 대상으로 하며 SDK에서 DynamoDB와 관련된 부분에만 초점을 맞춥니다.

AWS SDK에 대한 유지 관리 및 지원에 대한 자세한 내용은 AWS SDK 및 도구 참조 안내서의 AWS SDK and Tools maintenance policyAWS SDKs and Tools version support matrix를 참조하세요.

AWS SDK for Java 2.x에서 1.x 코드 베이스 상당수를 다시 작성했습니다. SDK for Java 2.x는 Java 8에 도입된 비차단 I/O와 같은 최신 Java 기능을 지원합니다. 또한, SDK for Java 2.x는 플러그형 HTTP 클라이언트 구현에 대한 지원을 추가하여 보다 많은 네트워크 연결 유연성과 구성 옵션을 제공합니다.

SDK for Java 1.x와 비교할 때 SDK for Java 2.x의 눈에 띄는 변화는 새로운 패키지 이름 사용입니다. Java 1.x SDK는 com.amazonaws 패키지 이름을 사용하는 반면 Java 2.x SDK는 software.amazon.awssdk 패키지 이름을 사용합니다. 마찬가지로 Java 1.x SDK용 Maven 아티팩트는 com.amazonaws groupId를 사용하는 반면, Java 2.x SDK 아티팩트는 software.amazon.awssdk groupId를 사용합니다.

중요

AWS SDK for Java 1.x에는 이름이 com.amazonaws.dynamodbv2인 DynamoDB 패키지가 있습니다. 패키지 이름의 'v2'는 해당 패키지가 Java 2(J2SE) 용이라는 의미가 아닙니다. 'v2'는 패키지가 하위 수준 API의 원래 버전 대신 DynamoDB 하위 수준 API의 두 번째 버전을 지원함을 나타냅니다.

Java 버전 지원

AWS SDK for Java 2.x는 장기 지원(LTS) Java 릴리스를 모두 지원합니다.

AWS SDK for Java 2.x 시작하기

다음 자습서에서는 Apache Maven을 사용하여 SDK for Java 2.x에 대한 종속성을 정의하는 방법을 보여줍니다. 또한 이 자습서에서는 사용 가능한 DynamoDB 테이블을 나열하기 위해 DynamoDB에 연결하는 코드를 작성하는 방법도 보여줍니다. 이 안내서의 자습서는 AWS SDK for Java 2.x 개발자 안내서에 있는 Get started with the AWS SDK for Java 2.x 자습서를 기반으로 합니다. Amazon S3 대신 DynamoDB를 직접 호출하도록 이 자습서를 편집했습니다.

1단계: 튜토리얼 설정

이 튜토리얼을 시작하기 전에 다음이 필요합니다.

  • DynamoDB에 액세스할 수 있는 권한

  • AWS 액세스 포털을 사용하여 AWS 서비스에 대한 SSO(Single Sign-On) 액세스로 구성된 Java 개발 환경

이 자습서를 설정하려면 AWS SDK for Java 2.x 개발자 안내서의 설정 개요에 있는 지침을 따르세요. Java SDK에 대한 SSO(Single Sign-On) 액세스로 개발 환경을 구성하고 활성 AWS 액세스 포털 세션이 있는 경우 이 자습서의 2단계로 계속 진행합니다.

2단계: 프로젝트 생성

이 자습서의 프로젝트를 생성하려면 프로젝트 구성 방법에 대한 입력을 요청하는 Maven 명령을 실행합니다. 모든 입력이 입력되고 확인되면 Maven은 pom.xml 파일을 생성하여 프로젝트 빌드를 완료하고 스텁 Java 파일을 생성합니다.

  1. 터미널 또는 명령 프롬프트 창을 열고 원하는 디렉터리 (예: Desktop 또는 Home 폴더)로 이동합니다.

  2. 터미널에서 다음 명령을 입력하고 Enter 키를 누릅니다.

    mvn archetype:generate \ -DarchetypeGroupId=software.amazon.awssdk \ -DarchetypeArtifactId=archetype-app-quickstart \ -DarchetypeVersion=2.22.0
  3. 각 프롬프트의 두 번째 열에 나열된 값을 입력합니다.

    프롬프트 입력할 값
    Define value for property 'service': dynamodb
    Define value for property 'httpClient': apache-client
    Define value for property 'nativeImage': false
    Define value for property 'credentialProvider' identity-center
    Define value for property 'groupId': org.example
    Define value for property 'artifactId': getstarted
    Define value for property 'version' 1.0-SNAPSHOT: <Enter>
    Define value for property 'package' org.example: <Enter>
  4. 마지막 값을 입력하면 Maven에서 선택한 항목을 나열합니다. 확인하려면 Y를 입력합니다. 아니면 N을 입력한 다음 선택 사항을 다시 입력합니다.

Maven은 입력한 artifactId 값을 기반으로 이름이 getstarted로 지정된 프로젝트 폴더를 만듭니다. getstarted 폴더 안에서 검토할 수 있는 README.md라는 이름의 파일, pom.xml 파일, src 디렉터리를 찾습니다.

Maven은 다음과 같은 디렉터리 트리를 만듭니다.

getstarted ├── README.md ├── pom.xml └── src ├── main │ ├── java │ │ └── org │ │ └── example │ │ ├── App.java │ │ ├── DependencyFactory.java │ │ └── Handler.java │ └── resources │ └── simplelogger.properties └── test └── java └── org └── example └── HandlerTest.java 10 directories, 7 files

다음은 pom.xml 프로젝트 파일의 콘텐츠를 보여줍니다.

dependencyManagement 섹션은 AWS SDK for Java 2.x에 대한 종속성을 포함하며 dependencies 섹션에는 DynamoDB에 대한 종속성이 있습니다. 이러한 종속성을 지정하면 Maven이 관련 .jar 파일을 Java 클래스 경로에 포함하도록 강제합니다. 기본적으로 AWS SDK에는 모든 AWS 서비스에 대한 클래스가 모두 포함되어 있지는 않습니다. DynamoDB의 경우 하위 수준 인터페이스를 사용하면 dynamodb 아티팩트에 대한 종속성이 있어야 합니다. 또는 상위 수준 인터페이스를 사용하는 경우 dynamodb-enhanced 아티팩트에 종속적이어야 합니다 관련 종속성을 포함하지 않으면 코드가 컴파일되지 않습니다. 프로젝트는 maven.compiler.sourcemaven.compiler.target 속성의 1.8 값 때문에 Java 1.8을 사용합니다.

<?xml version="1.0" encoding="UTF-8"?> <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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>getstarted</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.shade.plugin.version>3.2.1</maven.shade.plugin.version> <maven.compiler.plugin.version>3.6.1</maven.compiler.plugin.version> <exec-maven-plugin.version>1.6.0</exec-maven-plugin.version> <aws.java.sdk.version>2.22.0</aws.java.sdk.version> <-------- SDK version picked up from archetype version. <slf4j.version>1.7.28</slf4j.version> <junit5.version>5.8.1</junit5.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>bom</artifactId> <version>${aws.java.sdk.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>dynamodb</artifactId> <-------- DynamoDB dependency <exclusions> <exclusion> <groupId>software.amazon.awssdk</groupId> <artifactId>netty-nio-client</artifactId> </exclusion> <exclusion> <groupId>software.amazon.awssdk</groupId> <artifactId>apache-client</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>sso</artifactId> <-------- Required for identity center authentication. </dependency> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>ssooidc</artifactId> <-------- Required for identity center authentication. </dependency> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>apache-client</artifactId> <-------- HTTP client specified. <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>${slf4j.version}</version> </dependency> <!-- Needed to adapt Apache Commons Logging used by Apache HTTP Client to Slf4j to avoid ClassNotFoundException: org.apache.commons.logging.impl.LogFactoryImpl during runtime --> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>${slf4j.version}</version> </dependency> <!-- Test Dependencies --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>${junit5.version}</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>${maven.compiler.plugin.version}</version> </plugin> </plugins> </build> </project>

dependencyManagement 섹션은 AWS SDK for Java 2.x에 대한 종속성을 포함하며 dependencies 섹션에는 DynamoDB에 대한 종속성이 있습니다. 이러한 종속성을 지정하면 Maven이 관련 .jar 파일을 Java 클래스 경로에 포함하도록 강제합니다. 기본적으로 AWS SDK에는 모든 AWS 서비스에 대한 클래스가 모두 포함되어 있지는 않습니다. DynamoDB의 경우 하위 수준 인터페이스를 사용하면 dynamodb 아티팩트에 대한 종속성이 있어야 합니다. 또는 상위 수준 인터페이스를 사용하는 경우 dynamodb-enhanced 아티팩트에 종속적이어야 합니다 관련 종속성을 포함하지 않으면 코드가 컴파일되지 않습니다. 프로젝트는 maven.compiler.sourcemaven.compiler.target 속성의 1.8 값 때문에 Java 1.8을 사용합니다.

<?xml version="1.0" encoding="UTF-8"?> <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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>getstarted</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.shade.plugin.version>3.2.1</maven.shade.plugin.version> <maven.compiler.plugin.version>3.6.1</maven.compiler.plugin.version> <exec-maven-plugin.version>1.6.0</exec-maven-plugin.version> <aws.java.sdk.version>2.22.0</aws.java.sdk.version> <-------- SDK version picked up from archetype version. <slf4j.version>1.7.28</slf4j.version> <junit5.version>5.8.1</junit5.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>bom</artifactId> <version>${aws.java.sdk.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>dynamodb</artifactId> <-------- DynamoDB dependency <exclusions> <exclusion> <groupId>software.amazon.awssdk</groupId> <artifactId>netty-nio-client</artifactId> </exclusion> <exclusion> <groupId>software.amazon.awssdk</groupId> <artifactId>apache-client</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>sso</artifactId> <-------- Required for identity center authentication. </dependency> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>ssooidc</artifactId> <-------- Required for identity center authentication. </dependency> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>apache-client</artifactId> <-------- HTTP client specified. <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>${slf4j.version}</version> </dependency> <!-- Needed to adapt Apache Commons Logging used by Apache HTTP Client to Slf4j to avoid ClassNotFoundException: org.apache.commons.logging.impl.LogFactoryImpl during runtime --> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>${slf4j.version}</version> </dependency> <!-- Test Dependencies --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>${junit5.version}</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>${maven.compiler.plugin.version}</version> </plugin> </plugins> </build> </project>

3단계: 코드 작성

다음 코드는 Maven이 생성한 App 클래스를 보여줍니다. main 메서드는 Handler 클래스의 인스턴스를 만든 다음 해당 sendRequest 메서드를 호출하는 애플리케이션의 진입점입니다.

package org.example; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class App { private static final Logger logger = LoggerFactory.getLogger(App.class); public static void main(String... args) { logger.info("Application starts"); Handler handler = new Handler(); handler.sendRequest(); logger.info("Application ends"); } }

package org.example; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class App { private static final Logger logger = LoggerFactory.getLogger(App.class); public static void main(String... args) { logger.info("Application starts"); Handler handler = new Handler(); handler.sendRequest(); logger.info("Application ends"); } }

Maven에서 만든 DependencyFactory 클래스에는 DynamoDbClient 인스턴스를 빌드하고 반환하는 dynamoDbClient 팩토리 메서드가 포함되어 있습니다. DynamoDbClient 인스턴스는 Apache 기반 HTTP 클라이언트의 인스턴스를 사용합니다. 이는 Maven에서 사용할 HTTP 클라이언트를 묻는 메시지가 표시될 때 사용자가 apache-client를 지정했기 때문입니다.

다음 코드는 DependencyFactory 클래스를 보여줍니다.

package org.example; import software.amazon.awssdk.http.apache.ApacheHttpClient; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; /** * The module containing all dependencies required by the {@link Handler}. */ public class DependencyFactory { private DependencyFactory() {} /** * @return an instance of DynamoDbClient */ public static DynamoDbClient dynamoDbClient() { return DynamoDbClient.builder() .httpClientBuilder(ApacheHttpClient.builder()) .build(); } }

package org.example; import software.amazon.awssdk.http.apache.ApacheHttpClient; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; /** * The module containing all dependencies required by the {@link Handler}. */ public class DependencyFactory { private DependencyFactory() {} /** * @return an instance of DynamoDbClient */ public static DynamoDbClient dynamoDbClient() { return DynamoDbClient.builder() .httpClientBuilder(ApacheHttpClient.builder()) .build(); } }

Handler 클래스에는 프로그램의 기본 로직이 들어 있습니다. App 클래스에서 Handler 인스턴스가 생성되면 DependencyFactoryDynamoDbClient 서비스 클라이언트를 제공합니다. 코드는 DynamoDbClient 인스턴스를 사용하여 DynamoDB를 직접 호출합니다.

Maven은 TODO 주석과 함께 다음과 같은 Handler 클래스를 생성합니다. 자습서의 다음 단계에서는 TODO 주석을 코드로 대체합니다.

package org.example; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; public class Handler { private final DynamoDbClient dynamoDbClient; public Handler() { dynamoDbClient = DependencyFactory.dynamoDbClient(); } public void sendRequest() { // TODO: invoking the API calls using dynamoDbClient. } }

package org.example; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; public class Handler { private final DynamoDbClient dynamoDbClient; public Handler() { dynamoDbClient = DependencyFactory.dynamoDbClient(); } public void sendRequest() { // TODO: invoking the API calls using dynamoDbClient. } }

로직을 채우려면 Handler 클래스의 전체 내용을 다음 코드로 바꾸세요. sendRequest 메서드가 채워지고 필요한 임포트가 추가됩니다.

다음 코드는 DynamoDbClient 인스턴스를 사용하여 기존 테이블 목록을 검색합니다. 지정된 계정 및 AWS 리전에 대한 테이블이 있는 경우 코드는 Logger 인스턴스를 사용하여 이러한 테이블의 이름을 로깅합니다.

package org.example; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; import software.amazon.awssdk.services.dynamodb.model.ListTablesResponse; public class Handler { private final DynamoDbClient dynamoDbClient; public Handler() { dynamoDbClient = DependencyFactory.dynamoDbClient(); } public void sendRequest() { Logger logger = LoggerFactory.getLogger(Handler.class); logger.info("calling the DynamoDB API to get a list of existing tables"); ListTablesResponse response = dynamoDbClient.listTables(); if (!response.hasTableNames()) { logger.info("No existing tables found for the configured account & region"); } else { response.tableNames().forEach(tableName -> logger.info("Table: " + tableName)); } } }

다음 코드는 DynamoDbClient 인스턴스를 사용하여 기존 테이블 목록을 검색합니다. 지정된 계정 및 AWS 리전에 대한 테이블이 있는 경우 코드는 Logger 인스턴스를 사용하여 이러한 테이블의 이름을 로깅합니다.

package org.example; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; import software.amazon.awssdk.services.dynamodb.model.ListTablesResponse; public class Handler { private final DynamoDbClient dynamoDbClient; public Handler() { dynamoDbClient = DependencyFactory.dynamoDbClient(); } public void sendRequest() { Logger logger = LoggerFactory.getLogger(Handler.class); logger.info("calling the DynamoDB API to get a list of existing tables"); ListTablesResponse response = dynamoDbClient.listTables(); if (!response.hasTableNames()) { logger.info("No existing tables found for the configured account & region"); } else { response.tableNames().forEach(tableName -> logger.info("Table: " + tableName)); } } }

4단계: 애플리케이션 빌드 및 실행

프로젝트가 생성되고 전체 Handler 클래스가 포함된 후 애플리케이션을 빌드하고 실행합니다.

  1. AWS IAM Identity Center 세션이 활성화되어 있는지 확인합니다. 확인하려면 AWS Command Line Interface(AWS CLI) 명령 aws sts get-caller-identity를 실행하고 응답을 점검하세요. 활성 세션이 없는 경우 AWS CLI를 사용하여 로그인에서 지침을 확인하세요.

  2. 터미널 또는 명령 프롬프트 창을 열고 프로젝트 디렉토리 getstarted로 이동합니다.

  3. 프로젝트를 빌드하려면 다음 명령을 실행합니다.

    mvn clean package
  4. 애플리케이션을 실행하려면 다음 명령을 사용합니다.

    mvn exec:java -Dexec.mainClass="org.example.App"

파일을 확인한 후 객체를 삭제한 다음 버킷을 삭제합니다.

Success

Maven 프로젝트가 오류 없이 빌드되고 실행되었다면 축하합니다. SDK for Java 2.x를 사용한 첫 Java 애플리케이션 빌드에 성공했습니다.

정리

이 자습서를 진행하는 동안 만든 리소스를 정리하려면 getstarted 프로젝트 폴더를 삭제합니다.

AWS SDK for Java 2.x 문서 검토

AWS SDK for Java 2.x 개발자 안내서에서는 전 AWS 서비스에 걸쳐 SDK의 모든 측면을 전체적으로 다룹니다. 다음 주제를 검토하는 것이 좋습니다.

  • Migrate from version 1.x to 2.x - 1.x와 2.x의 차이점에 대한 자세한 설명이 포함되어 있습니다. 이 주제에는 두 주요 버전을 나란히 사용하는 방법에 대한 지침도 포함되어 있습니다.

  • DynamoDB guide for Java 2.x SDK - 테이블 생성, 항목 조작, 항목 검색 등 기본적인 DynamoDB 작업을 수행하는 방법을 보여줍니다. 이 예에서는 하위 수준 인터페이스를 사용합니다. Java에는 지원되는 인터페이스 섹션에 설명된 대로 여러 인터페이스가 있습니다.

작은 정보

이러한 주제를 검토한 후 AWS SDK for Java 2.x API 참조를 북마크하세요. 모든 AWS 서비스를 다루며 기본 API 참조로 사용하는 것이 좋습니다.

지원되는 인터페이스

AWS SDK for Java 2.x는 원하는 추상화 수준에 따라 다음 인터페이스를 지원합니다.

하위 수준 인터페이스

하위 수준 인터페이스는 기본 서비스 API에 대한 일대일 매핑을 제공합니다. 이 인터페이스를 통해 모든 DynamoDB API를 사용할 수 있습니다. 즉, 하위 수준 인터페이스가 완전한 기능을 제공할 수 있지만 사용하기가 더 복잡한 경우가 많습니다. 예를 들어, .s() 함수를 사용하여 문자열을 저장하고 .n() 함수를 사용하여 숫자를 저장합니다. 다음 PutItem 예시는 하위 수준 인터페이스를 사용하여 항목을 삽입합니다.

import org.slf4j.*; import software.amazon.awssdk.http.crt.AwsCrtHttpClient; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; import software.amazon.awssdk.services.dynamodb.model.*; import java.util.Map; public class PutItem { // Create a DynamoDB client with the default settings connected to the DynamoDB // endpoint in the default region based on the default credentials provider chain. private static final DynamoDbClient DYNAMODB_CLIENT = DynamoDbClient.create(); private static final Logger LOGGER = LoggerFactory.getLogger(PutItem.class); private void putItem() { PutItemResponse response = DYNAMODB_CLIENT.putItem(PutItemRequest.builder() .item(Map.of( "pk", AttributeValue.builder().s("123").build(), "sk", AttributeValue.builder().s("cart#123").build(), "item_data", AttributeValue.builder().s("YourItemData").build(), "inventory", AttributeValue.builder().n("500").build() // ... more attributes ... )) .returnConsumedCapacity(ReturnConsumedCapacity.TOTAL) .tableName("YourTableName") .build()); LOGGER.info("PutItem call consumed [" + response.consumedCapacity().capacityUnits() + "] Write Capacity Unites (WCU)"); } }

상위 수준 인터페이스

AWS SDK for Java 2.x의 상위 수준 인터페이스를 DynamoDB 향상된 클라이언트라고 합니다. 이 인터페이스는 보다 관용적인 코드 작성 경험을 제공합니다.

향상된 클라이언트는 클라이언트 측 데이터 클래스와 해당 데이터를 저장하도록 설계된 DynamoDB 테이블 간에 매핑하는 방법을 제공합니다. 코드에서 테이블과 해당 모델 클래스 간의 관계를 정의합니다. 그러면 SDK를 사용하여 데이터 유형 조작을 관리할 수 있습니다. 향상된 클라이언트에 대한 자세한 내용은 AWS SDK for Java 2.x 개발자 안내서의 DynamoDB enhanced client API를 참조하세요.

다음 PutItem 예시에서는 상위 수준 인터페이스를 사용합니다. 이 예제에서는 YourItem이라는 DynamoDbBeanTableSchema를 만들어 putItem() 직접 호출의 입력으로 바로 사용할 수 있도록 합니다.

import org.slf4j.*; import software.amazon.awssdk.enhanced.dynamodb.*; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.*; import software.amazon.awssdk.enhanced.dynamodb.model.*; import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity; public class DynamoDbEnhancedClientPutItem { private static final DynamoDbEnhancedClient ENHANCED_DYNAMODB_CLIENT = DynamoDbEnhancedClient.builder().build(); private static final DynamoDbTable<YourItem> DYNAMODB_TABLE = ENHANCED_DYNAMODB_CLIENT.table("YourTableName", TableSchema.fromBean(YourItem.class)); private static final Logger LOGGER = LoggerFactory.getLogger(PutItem.class); private void putItem() { PutItemEnhancedResponse<YourItem> response = DYNAMODB_TABLE.putItemWithResponse(PutItemEnhancedRequest.builder(YourItem.class) .item(new YourItem("123", "cart#123", "YourItemData", 500)) .returnConsumedCapacity(ReturnConsumedCapacity.TOTAL) .build()); LOGGER.info("PutItem call consumed [" + response.consumedCapacity().capacityUnits() + "] Write Capacity Unites (WCU)"); } @DynamoDbBean public static class YourItem { public YourItem() {} public YourItem(String pk, String sk, String itemData, int inventory) { this.pk = pk; this.sk = sk; this.itemData = itemData; this.inventory = inventory; } private String pk; private String sk; private String itemData; private int inventory; @DynamoDbPartitionKey public void setPk(String pk) { this.pk = pk; } public String getPk() { return pk; } @DynamoDbSortKey public void setSk(String sk) { this.sk = sk; } public String getSk() { return sk; } public void setItemData(String itemData) { this.itemData = itemData; } public String getItemData() { return itemData; } public void setInventory(int inventory) { this.inventory = inventory; } public int getInventory() { return inventory; } } }

AWS SDK for Java 1.x에는 자체 상위 수준 인터페이스가 있으며, 이 인터페이스는 주로 기본 클래스 DynamoDBMapper에서 참조합니다. AWS SDK for Java 2.x는 software.amazon.awssdk.enhanced.dynamodb라는 별도의 패키지(및 Maven 아티팩트)에 게시됩니다. Java 2.x SDK는 주로 기본 클래스 DynamoDbEnhancedClient에서 참조합니다.

변경할 수 없는 데이터 클래스를 사용하는 상위 수준 인터페이스

DynamoDB 향상된 클라이언트 API의 매핑 기능은 변경 불가능한 데이터 클래스와도 함께 작동합니다. 불변 클래스에는 접근자만 포함되며 SDK가 클래스의 인스턴스를 생성하는 데 사용하는 빌더 클래스가 필요합니다. Java의 불변성은 개발자가 부작용이 없는 클래스를 만드는 데 사용할 수 있는 일반적으로 사용되는 스타일입니다. 복잡한 멀티스레드 애플리케이션에서는 이러한 클래스의 동작을 더 잘 예측할 수 있습니다. 변경 불가능한 클래스는 High-level interface example에 나온 대로 @DynamoDbBean 주석을 사용하는 대신 빌더 클래스를 입력으로 사용하는 @DynamoDbImmutable 주석을 사용합니다.

다음 예시에서는 빌더 클래스 DynamoDbEnhancedClientImmutablePutItem을 입력으로 사용하여 테이블 스키마를 생성합니다. 그런 다음 예시는 PutItem API 직접 호출을 위한 입력으로 해당 스키마를 제공합니다.

import org.slf4j.*; import software.amazon.awssdk.enhanced.dynamodb.*; import software.amazon.awssdk.enhanced.dynamodb.model.*; import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity; public class DynamoDbEnhancedClientImmutablePutItem { private static final DynamoDbEnhancedClient ENHANCED_DYNAMODB_CLIENT = DynamoDbEnhancedClient.builder().build(); private static final DynamoDbTable<YourImmutableItem> DYNAMODB_TABLE = ENHANCED_DYNAMODB_CLIENT.table("YourTableName", TableSchema.fromImmutableClass(YourImmutableItem.class)); private static final Logger LOGGER = LoggerFactory.getLogger(DynamoDbEnhancedClientImmutablePutItem.class); private void putItem() { PutItemEnhancedResponse<YourImmutableItem> response = DYNAMODB_TABLE.putItemWithResponse(PutItemEnhancedRequest.builder(YourImmutableItem.class) .item(YourImmutableItem.builder() .pk("123") .sk("cart#123") .itemData("YourItemData") .inventory(500) .build()) .returnConsumedCapacity(ReturnConsumedCapacity.TOTAL) .build()); LOGGER.info("PutItem call consumed [" + response.consumedCapacity().capacityUnits() + "] Write Capacity Unites (WCU)"); } }

다음 예시에서는 변경 불가능한 데이터 클래스를 보여줍니다.

@DynamoDbImmutable(builder = YourImmutableItem.YourImmutableItemBuilder.class) class YourImmutableItem { private final String pk; private final String sk; private final String itemData; private final int inventory; public YourImmutableItem(YourImmutableItemBuilder builder) { this.pk = builder.pk; this.sk = builder.sk; this.itemData = builder.itemData; this.inventory = builder.inventory; } public static YourImmutableItemBuilder builder() { return new YourImmutableItemBuilder(); } @DynamoDbPartitionKey public String getPk() { return pk; } @DynamoDbSortKey public String getSk() { return sk; } public String getItemData() { return itemData; } public int getInventory() { return inventory; } static final class YourImmutableItemBuilder { private String pk; private String sk; private String itemData; private int inventory; private YourImmutableItemBuilder() {} public YourImmutableItemBuilder pk(String pk) { this.pk = pk; return this; } public YourImmutableItemBuilder sk(String sk) { this.sk = sk; return this; } public YourImmutableItemBuilder itemData(String itemData) { this.itemData = itemData; return this; } public YourImmutableItemBuilder inventory(int inventory) { this.inventory = inventory; return this; } public YourImmutableItem build() { return new YourImmutableItem(this); } } }

변경 불가능한 데이터 클래스와 서드 파티 보일러플레이트 생성 라이브러리를 사용하는 상위 수준 인터페이스

이전 예제에서 언급한 변경 불가능한 데이터 클래스에는 몇 가지 보일러플레이트 코드가 필요합니다. 예를 들어, Builder 클래스 외에 데이터 클래스의 게터 및 세터 로직이 필요합니다. Project Lombok과 같은 서드 파티 라이브러리는 이러한 유형의 보일러플레이트 코드를 생성하는 데 도움이 될 수 있습니다. 대부분의 보일러플레이트 코드를 줄이면 변경 불가능한 데이터 클래스와 AWS SDK를 사용하는 데 필요한 코드의 양을 제한할 수 있습니다. 이를 통해 코드의 생산성과 가독성이 더욱 향상됩니다. AWS SDK for Java 2.x 자세한 내용은 개발자 안내서의 Lombok과 같은 타사 라이브러리를 사용을 참조하세요.

다음 예시는 Project Lombok이 DynamoDB 향상된 클라이언트 API를 사용하는 데 필요한 코드를 간소화하는 방법을 보여줍니다.

import org.slf4j.*; import software.amazon.awssdk.enhanced.dynamodb.*; import software.amazon.awssdk.enhanced.dynamodb.model.*; import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity; public class DynamoDbEnhancedClientImmutableLombokPutItem { private static final DynamoDbEnhancedClient ENHANCED_DYNAMODB_CLIENT = DynamoDbEnhancedClient.builder().build(); private static final DynamoDbTable<YourImmutableLombokItem> DYNAMODB_TABLE = ENHANCED_DYNAMODB_CLIENT.table("YourTableName", TableSchema.fromImmutableClass(YourImmutableLombokItem.class)); private static final Logger LOGGER = LoggerFactory.getLogger(DynamoDbEnhancedClientImmutableLombokPutItem.class); private void putItem() { PutItemEnhancedResponse<YourImmutableLombokItem> response = DYNAMODB_TABLE.putItemWithResponse(PutItemEnhancedRequest.builder(YourImmutableLombokItem.class) .item(YourImmutableLombokItem.builder() .pk("123") .sk("cart#123") .itemData("YourItemData") .inventory(500) .build()) .returnConsumedCapacity(ReturnConsumedCapacity.TOTAL) .build()); LOGGER.info("PutItem call consumed [" + response.consumedCapacity().capacityUnits() + "] Write Capacity Unites (WCU)"); } }

다음 예시에서는 변경 불가능한 데이터 클래스의 변경 불가능한 데이터 객체를 보여줍니다.

import lombok.*; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.*; @Builder @DynamoDbImmutable(builder = YourImmutableLombokItem.YourImmutableLombokItemBuilder.class) @Value public class YourImmutableLombokItem { @Getter(onMethod_=@DynamoDbPartitionKey) String pk; @Getter(onMethod_=@DynamoDbSortKey) String sk; String itemData; int inventory; }

YourImmutableLombokItem 클래스는 Project Lombok 및 AWS SDK에서 제공하는 다음과 같은 주석을 사용합니다.

  • @Builder - Project Lombok에서 제공하는 데이터 클래스를 위한 복잡한 빌더 API를 생성합니다.

  • @DynamoDbImmutable - DynamoDbImmutable 클래스를 AWS SDK에서 제공하는 DynamoDB 매핑 가능한 엔터티 주석으로 식별합니다.

  • @Value - @Data의 변경할 수 없는 변형입니다. 기본적으로 모든 필드는 비공개 및 최종본으로 설정되고 세터가 생성되지 않습니다. Project Lombok은 이 주석을 제공합니다.

문서 인터페이스

AWS SDK for Java 2.x 문서 인터페이스를 사용하면 데이터 유형 설명자를 지정할 필요가 없습니다. 데이터 형식은 데이터 자체의 의미론으로 암시됩니다. 이 문서 인터페이스는 AWS SDK for Java 1.x, 문서 인터페이스와 비슷하지만, 인터페이스가 새롭게 디자인되었습니다.

다음 Document interface example는 Document 인터페이스를 사용하여 표현된 PutItem 직접 호출을 보여줍니다. 이 예시에서는 EnhancedDocument도 사용합니다. 향상된 문서 API를 사용하여 DynamoDB 테이블에 대해 명령을 실행하려면 먼저 테이블을 문서 테이블 스키마와 연결하여 DynamoDBTable 리소스 개체를 생성해야 합니다. 문서 테이블 스키마 빌더에는 기본 인덱스 키와 속성 변환기 제공자가 필요합니다.

AttributeConverterProvider.defaultProvider()를 사용하여 기본 유형의 문서 속성을 변환할 수 있습니다. 사용자 지정 AttributeConverterProvider 구현으로 전체 기본 동작을 변경할 수 있습니다. 단일 속성의 변환기를 변경할 수도 있습니다. AWS SDK 및 도구 참조 안내서에는 사용자 지정 변환기를 사용하는 방법에 대한 자세한 내용과 예제가 나와 있습니다. 기본적인 용도는 기본 변환기를 사용할 수 없는 도메인 클래스의 속성을 위한 것입니다. 사용자 지정 변환기를 사용하면 DynamoDB에 쓰거나 읽는 데 필요한 정보를 SDK에 제공할 수 있습니다.

import org.slf4j.*; import software.amazon.awssdk.enhanced.dynamodb.*; import software.amazon.awssdk.enhanced.dynamodb.document.EnhancedDocument; import software.amazon.awssdk.enhanced.dynamodb.model.*; import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity; public class DynamoDbEnhancedDocumentClientPutItem { private static final DynamoDbEnhancedClient ENHANCED_DYNAMODB_CLIENT = DynamoDbEnhancedClient.builder().build(); private static final DynamoDbTable<EnhancedDocument> DYNAMODB_TABLE = ENHANCED_DYNAMODB_CLIENT.table("YourTableName", TableSchema.documentSchemaBuilder() .addIndexPartitionKey(TableMetadata.primaryIndexName(),"pk", AttributeValueType.S) .addIndexSortKey(TableMetadata.primaryIndexName(), "sk", AttributeValueType.S) .attributeConverterProviders(AttributeConverterProvider.defaultProvider()) .build()); private static final Logger LOGGER = LoggerFactory.getLogger(DynamoDbEnhancedDocumentClientPutItem.class); private void putItem() { PutItemEnhancedResponse<EnhancedDocument> response = DYNAMODB_TABLE.putItemWithResponse( PutItemEnhancedRequest.builder(EnhancedDocument.class) .item( EnhancedDocument.builder() .attributeConverterProviders(AttributeConverterProvider.defaultProvider()) .putString("pk", "123") .putString("sk", "cart#123") .putString("item_data", "YourItemData") .putNumber("inventory", 500) .build()) .returnConsumedCapacity(ReturnConsumedCapacity.TOTAL) .build()); LOGGER.info("PutItem call consumed [" + response.consumedCapacity().capacityUnits() + "] Write Capacity Unites (WCU)"); } }

다음 유틸리티 메서드를 사용하여 JSON 문서를 기본 Amazon DynamoDB 데이터 유형으로, 또 그 반대로 변환할 수 있습니다.

Query 예제와 인터페이스 비교

이 섹션에서는 다양한 인터페이스를 사용하여 동일한 Query 직접 호출을 표현한 것을 보여줍니다. 이러한 쿼리의 결과를 세밀하게 조정하려면 다음 사항에 유의하세요.

  • DynamoDB는 하나의 특정 파티션 키 값을 대상으로 하므로, 파티션 키를 완전히 지정해야 합니다.

  • 정렬 키에는 카트 항목만 이 쿼리의 대상으로 지정되도록 begins_with를 사용하는 키 조건 표현식이 있습니다.

  • 쿼리를 최대 100개의 반환 항목으로 제한하는 데 limit()을 사용합니다.

  • scanIndexForward를 false로 설정합니다. 결과는 UTF-8 바이트 순으로 반환되며, 이는 일반적으로 숫자가 가장 작은 카트 항목이 먼저 반환됨을 의미합니다. scanIndexForward를 false로 설정하면 순서가 반대가 되고 숫자가 가장 큰 카트 항목이 먼저 반환됩니다.

  • 필터를 적용하여 기준과 일치하지 않는 모든 결과를 제거합니다. 필터링되는 데이터는 항목이 필터와 일치하는지와 관계없이 읽기 용량을 소비합니다.

예 하위 수준 인터페이스를 사용한 Query

다음 예제에서는 keyConditionExpression를 사용하여 이름이 YourTableName인 테이블을 쿼리합니다. 이를 통해 쿼리를 특정 파티션 키 값 및 특정 접두사 값으로 시작하는 정렬 키 값으로 제한합니다. 이러한 키 조건은 DynamoDB에서 읽는 데이터의 양을 제한합니다. 마지막으로 쿼리는 filterExpression을 사용하여 DynamoDB에서 검색한 데이터에 필터를 적용합니다.

import org.slf4j.*; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; import software.amazon.awssdk.services.dynamodb.model.*; import java.util.Map; public class Query { // Create a DynamoDB client with the default settings connected to the DynamoDB // endpoint in the default region based on the default credentials provider chain. private static final DynamoDbClient DYNAMODB_CLIENT = DynamoDbClient.builder().build(); private static final Logger LOGGER = LoggerFactory.getLogger(Query.class); private static void query() { QueryResponse response = DYNAMODB_CLIENT.query(QueryRequest.builder() .expressionAttributeNames(Map.of("#name", "name")) .expressionAttributeValues(Map.of( ":pk_val", AttributeValue.fromS("id#1"), ":sk_val", AttributeValue.fromS("cart#"), ":name_val", AttributeValue.fromS("SomeName"))) .filterExpression("#name = :name_val") .keyConditionExpression("pk = :pk_val AND begins_with(sk, :sk_val)") .limit(100) .scanIndexForward(false) .tableName("YourTableName") .build()); LOGGER.info("nr of items: " + response.count()); LOGGER.info("First item pk: " + response.items().get(0).get("pk")); LOGGER.info("First item sk: " + response.items().get(0).get("sk")); } }
예 문서 인터페이스를 사용한 Query

다음 예제에서는 문서 인터페이스를 사용하여 이름이 YourTableName인 테이블을 쿼리합니다.

import org.slf4j.Logger; import org.slf4j.LoggerFactory; import software.amazon.awssdk.enhanced.dynamodb.*; import software.amazon.awssdk.enhanced.dynamodb.document.EnhancedDocument; import software.amazon.awssdk.enhanced.dynamodb.model.*; import java.util.Map; public class DynamoDbEnhancedDocumentClientQuery { // Create a DynamoDB client with the default settings connected to the DynamoDB // endpoint in the default region based on the default credentials provider chain. private static final DynamoDbEnhancedClient ENHANCED_DYNAMODB_CLIENT = DynamoDbEnhancedClient.builder().build(); private static final DynamoDbTable<EnhancedDocument> DYNAMODB_TABLE = ENHANCED_DYNAMODB_CLIENT.table("YourTableName", TableSchema.documentSchemaBuilder() .addIndexPartitionKey(TableMetadata.primaryIndexName(),"pk", AttributeValueType.S) .addIndexSortKey(TableMetadata.primaryIndexName(), "sk", AttributeValueType.S) .attributeConverterProviders(AttributeConverterProvider.defaultProvider()) .build()); private static final Logger LOGGER = LoggerFactory.getLogger(DynamoDbEnhancedDocumentClientQuery.class); private void query() { PageIterable<EnhancedDocument> response = DYNAMODB_TABLE.query(QueryEnhancedRequest.builder() .filterExpression(Expression.builder() .expression("#name = :name_val") .expressionNames(Map.of("#name", "name")) .expressionValues(Map.of(":name_val", AttributeValue.fromS("SomeName"))) .build()) .limit(100) .queryConditional(QueryConditional.sortBeginsWith(Key.builder() .partitionValue("id#1") .sortValue("cart#") .build())) .scanIndexForward(false) .build()); LOGGER.info("nr of items: " + response.items().stream().count()); LOGGER.info("First item pk: " + response.items().iterator().next().getString("pk")); LOGGER.info("First item sk: " + response.items().iterator().next().getString("sk")); } }
예 상위 수준 인터페이스를 사용한 Query

다음 예시는 DynamoDB 향상된 클라이언트 API를 사용하여 이름이 YourTableName인 테이블을 쿼리합니다.

import org.slf4j.*; import software.amazon.awssdk.enhanced.dynamodb.*; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.*; import software.amazon.awssdk.enhanced.dynamodb.model.*; import software.amazon.awssdk.services.dynamodb.model.AttributeValue; import java.util.Map; public class DynamoDbEnhancedClientQuery { private static final DynamoDbEnhancedClient ENHANCED_DYNAMODB_CLIENT = DynamoDbEnhancedClient.builder().build(); private static final DynamoDbTable<YourItem> DYNAMODB_TABLE = ENHANCED_DYNAMODB_CLIENT.table("YourTableName", TableSchema.fromBean(DynamoDbEnhancedClientQuery.YourItem.class)); private static final Logger LOGGER = LoggerFactory.getLogger(DynamoDbEnhancedClientQuery.class); private void query() { PageIterable<YourItem> response = DYNAMODB_TABLE.query(QueryEnhancedRequest.builder() .filterExpression(Expression.builder() .expression("#name = :name_val") .expressionNames(Map.of("#name", "name")) .expressionValues(Map.of(":name_val", AttributeValue.fromS("SomeName"))) .build()) .limit(100) .queryConditional(QueryConditional.sortBeginsWith(Key.builder() .partitionValue("id#1") .sortValue("cart#") .build())) .scanIndexForward(false) .build()); LOGGER.info("nr of items: " + response.items().stream().count()); LOGGER.info("First item pk: " + response.items().iterator().next().getPk()); LOGGER.info("First item sk: " + response.items().iterator().next().getSk()); } @DynamoDbBean public static class YourItem { public YourItem() {} public YourItem(String pk, String sk, String name) { this.pk = pk; this.sk = sk; this.name = name; } private String pk; private String sk; private String name; @DynamoDbPartitionKey public void setPk(String pk) { this.pk = pk; } public String getPk() { return pk; } @DynamoDbSortKey public void setSk(String sk) { this.sk = sk; } public String getSk() { return sk; } public void setName(String name) { this.name = name; } public String getName() { return name; } } }
변경할 수 없는 데이터 클래스를 사용하는 상위 수준 인터페이스

상위 수준의 변경 불가능한 데이터 클래스를 사용하여 Query를 수행하는 경우 엔터티 클래스 YourItem 또는 YourImmutableItem의 구성을 제외하면 코드는 상위 수준 인터페이스 예제와 동일합니다. 자세한 내용은 PutItem 예시를 참조하세요.

변경 불가능한 데이터 클래스와 서드 파티 보일러플레이트 생성 라이브러리를 사용하는 상위 수준 인터페이스

상위 수준의 변경 불가능한 데이터 클래스를 사용하여 Query를 수행하는 경우 엔터티 클래스 YourItem 또는 YourImmutableLombokItem의 구성을 제외하면 코드는 상위 수준 인터페이스 예제와 동일합니다. 자세한 내용은 PutItem 예시를 참조하세요.

추가 코드 예시

SDK for Java 2.x와 함께 DynamoDB를 사용하는 방법에 대한 추가 예제는 다음 코드 예제 리포지토리를 참조하세요.

동기식 및 비동기식 프로그래밍

AWS SDK for Java 2.x는 DynamoDB와 같은 AWS 서비스에 동기식 클라이언트와 비동기식 클라이언트를 모두 제공합니다.

DynamoDbClientDynamoDbEnhancedClient 클래스는 클라이언트가 서비스로부터 응답을 받을 때까지 스레드의 실행을 차단하는 동기식 메서드를 제공합니다. 이 클라이언트는 비동기식 작업이 필요 없는 경우 DynamoDB와 상호 작용하는 가장 간단한 방법입니다.

DynamoDbAsyncClientDynamoDbEnhancedAsyncClient 클래스는 즉시 반환하는 비동기식 메서드를 제공하며, 응답을 기다리지 않고 제어 권한을 직접 호출하는 스레드에 넘겨줍니다. 비차단 클라이언트는 몇 개의 스레드에서 높은 동시성을 사용하여 최소한의 컴퓨팅 리소스로 I/O 요청을 효율적으로 처리할 수 있다는 이점이 있습니다. 이를 통해 처리량과 응답성이 향상됩니다.

AWS SDK for Java 2.x는 비차단 I/O에 대한 기본 지원을 사용합니다. AWS SDK for Java 1.x는 비차단 I/O를 시뮬레이션해야 했습니다.

동기식 메서드는 응답이 제공되기 전에 반환하므로, 준비되었을 때 응답을 가져올 방법이 필요합니다. AWS SDK for Java의 비동기식 메서드는 미래의 비동기식 작업 결과를 포함하는 CompletableFuture 객체를 반환합니다. 이러한 CompletableFuture 개체에서 get() 또는 join()을 직접 호출하면 결과가 나올 때까지 코드가 차단됩니다. 요청과 동시에 직접 호출을 수행하면 일반 동기식 직접 호출과 동작이 비슷합니다.

비동기 프로그래밍에 대한 자세한 내용은 AWS SDK for Java 2.x 개발자 안내서의 Use asynchronous programming을 참조하세요.

HTTP 클라이언트

모든 클라이언트를 지원하기 위해 AWS 서비스와의 통신을 처리하는 HTTP 클라이언트가 있습니다. 애플리케이션에 가장 적합한 특성을 가진 클라이언트를 선택하여 대체 HTTP 클라이언트를 연결할 수 있습니다. 어떤 것은 더 가볍고 어떤 것은 더 많은 구성 옵션을 제공합니다.

어떤 HTTP 클라이언트는 동기식 사용만 지원하는 반면 어떤 HTTP 클라이언트는 비동기식 사용만 지원합니다. 워크로드에 적합한 HTTP 클라이언트를 선택하는 데 도움이 되는 흐름도는 AWS SDK for Java 2.x 개발자 안내서의 HTTP 클라이언트 권장 사항에서 참조하세요.

다음 목록은 가능한 HTTP 클라이언트 중 일부를 보여줍니다.

Apache 기반 HTTP 클라이언트

ApacheHttpClient 클래스는 동기식 서비스 클라이언트를 지원합니다. 동기식 사용의 기본 HTTP 클라이언트입니다. ApacheHttpClient 클래스 구성에 대한 자세한 내용은 AWS SDK for Java 2.x 개발자 안내서의 Configure the Apache-based HTTP client에서 참조하세요.

URLConnection 기반 HTTP 클라이언트

UrlConnectionHttpClient 클래스는 동기식 클라이언트를 위한 또 다른 옵션입니다. Apache 기반 HTTP 클라이언트보다 로드 속도가 빠르지만 기능이 더 적습니다. UrlConnectionHttpClient 클래스 구성에 대한 자세한 내용은 AWS SDK for Java 2.x 개발자 안내서의 Configure the URLConnection-based HTTP client에서 참조하세요.

Netty 기반 HTTP 클라이언트

NettyNioAsyncHttpClient 클래스는 비동기식 클라이언트를 지원합니다. 비동기식으로 사용 시 기본으로 선택됩니다. NettyNioAsyncHttpClient 클래스 구성에 대한 자세한 내용은 AWS SDK for Java 2.x 개발자 안내서의 Configure the Netty-based HTTP client에서 참조하세요.

AWS CRT 기반 HTTP 클라이언트

AWS Common Runtime(CRT) 라이브러리의 최신 AwsCrtHttpClientAwsCrtAsyncHttpClient 클래스는 동기식 및 비동기식 클라이언트를 지원하는 더 많은 옵션입니다. 다른 HTTP 클라이언트와 비교하여 AWS CRT는 다음을 제공합니다.

  • 더 빠른 SDK 시작 시간

  • 더 작은 메모리 공간

  • 대기 시간 단축

  • 연결 상태 관리

  • DNS 로드 밸런싱

AwsCrtHttpClientAwsCrtAsyncHttpClient 클래스 구성에 대한 자세한 내용은 AWS SDK for Java 2.x 개발자 안내서의 Configure the AWS CRT-based HTTP clients에서 참조하세요.

AWS CRT 기반 HTTP 클라이언트는 기존 애플리케이션의 하위 호환성을 깨뜨릴 수 있으므로, 기본값이 아닙니다. 하지만 DynamoDB의 경우 동기식 및 비동기식 사용에 AWS CRT 기반 HTTP 클라이언트를 사용하는 것이 좋습니다.

AWS CRT 기반 HTTP 클라이언트에 대한 소개는 AWS 개발자 도구 블로그의 Announcing availability of the AWS CRT HTTP Client in the AWS SDK for Java 2.x에서 참조하세요.

HTTP 클라이언트 구성

클라이언트를 구성할 때 다음과 같은 다양한 구성 옵션을 제공할 수 있습니다.

  • API 직접 호출의 다양한 측면에 대한 제한 시간 설정.

  • TCP 연결 유지 활성화.

  • 오류 발생 시 재시도 정책 제어.

  • 실행 인터셉터 인스턴스가 수정할 수 있는 실행 속성 지정. 실행 인터셉터는 API 요청 및 응답의 실행을 가로채는 코드를 작성할 수 있습니다. 이를 통해 지표를 게시하고 진행 중인 요청을 수정하는 등의 작업을 수행할 수 있습니다.

  • HTTP 헤더 추가 또는 조작.

  • 클라이언트 측 성능 지표 추적 활성화. 이 기능을 사용하면 애플리케이션의 서비스 클라이언트에 대한 지표를 수집하고 Amazon CloudWatch에서 출력을 분석할 수 있습니다.

  • 비동기식 재시도 및 제한 시간 작업과 같은 일정 예약 작업에 사용할 대체 실행자 서비스 지정.

서비스 클라이언트 Builder 클래스에 ClientOverrideConfiguration 객체를 제공하여 구성을 제어합니다. 다음 섹션의 일부 코드 예시에서 이를 확인할 수 있습니다.

ClientOverrideConfiguration은 표준 구성 선택 사항을 제공합니다. 다양한 플러그 가능 HTTP 클라이언트에는 구현별 구성 기능도 있습니다.

제한 시간 구성

클라이언트 구성을 조정하여 서비스 직접 호출과 관련된 다양한 제한 시간을 제어할 수 있습니다. DynamoDB는 다른 AWS 서비스에 비해 지연 시간이 더 짧습니다. 따라서 네트워킹 문제가 발생할 경우 빠르게 실패할 수 있도록 이러한 속성을 조정하여 제한 시간 값을 낮추는 것이 좋습니다.

DynamoDB 클라이언트에서 ClientOverrideConfiguration을 사용하거나 기본 HTTP 클라이언트 구현에서 세부 구성 옵션을 변경하여 지연 시간 관련 동작을 사용자 지정할 수 있습니다.

ClientOverrideConfiguration을 사용하여 다음과 같은 영향력 있는 속성을 구성할 수 있습니다.

  • apiCallAttemptTimeout – 포기하고 제한 시간이 초과되기 전에 한 번의 HTTP 요청 시도가 완료되기까지 기다리는 시간입니다.

  • apiCallTimeout – 클라이언트가 API 직접 호출을 완전히 실행해야 하는 시간입니다. 여기에는 재시도를 포함한 모든 HTTP 요청으로 구성된 요청 핸들러 실행이 포함됩니다.

AWS SDK for Java 2.x는 연결 제한 시간 및 소켓 제한 시간 등의 일부 제한 시간 옵션에 기본값을 제공합니다. SDK는 API 직접 호출 제한 시간 또는 개별 API 직접 호출 시도 제한 시간에 기본값을 제공하지 않습니다. 이러한 제한 시간이 ClientOverrideConfiguration에 설정되지 않은 경우 SDK는 전체 API 직접 호출 제한 시간 대신 소켓 제한 시간 값을 사용합니다. 소켓 제한 시간의 기본값은 30초입니다.

RetryMode

제한 시간 구성과 관련하여 고려해야 하는 또 다른 구성은 RetryMode 구성 객체입니다. 이 구성 객체에는 재시도 동작 모음이 포함되어 있습니다.

SDK for Java 2.x는 다음 재시도 모드를 지원합니다.

  • legacy – 명시적으로 변경하지 않는 경우 기본 재시도 모드입니다. 이 재시도 모드는 Java SDK에만 해당됩니다. 최대 3회 재시도 또는 DynamoDB와 같은 서비스의 경우 최대 8회 재시도할 수 있습니다.

  • standard - 다른 AWS SDK와 더 일관적이기 때문에 '표준'이라는 이름이 지정되었습니다. 이 모드는 첫 번째 재시도를 위해 0ms에서 1,000ms 사이의 임의의 시간 동안 기다립니다. 다시 재시도해야 하는 경우 이 모드는 0ms에서 1,000ms 사이의 또 다른 임의의 시간을 선택하여 2를 곱합니다. 추가 재시도가 필요한 경우 같은 범위에서 임의로 선택한 시간에 4를 곱하는 식으로 반복합니다. 각 대기 시간은 20초로 제한됩니다. 이 모드는 legacy 모드보다 더 많이 감지된 장애 조건에 대해 재시도를 수행합니다. DynamoDB의 경우 numRetries로 재정의하지 않는 한 모두 합쳐 최대 3회까지 시도합니다.

  • adaptivestandard 모드를 기반으로 하며 AWS 요청 비율을 동적으로 제한하여 성공률을 극대화합니다. 이렇게 하면 요청 지연 시간이 길어질 수 있습니다. 예측 가능한 지연 시간이 중요한 경우에는 적응형 재시도 모드를 사용하지 않는 것이 좋습니다.

이러한 재시도 모드의 확장된 정의는 AWS SDK 및 도구 참조 안내서의 Retry behavior에서 확인할 수 있습니다.

재시도 정책

모든 RetryMode 구성에는 하나 이상의 RetryCondition 구성을 기반으로 구축된 RetryPolicy가 있습니다. TokenBucketRetryCondition은 DynamoDB SDK 클라이언트 구현의 재시도 동작에 특히 중요합니다. 이 조건은 토큰 버킷 알고리즘을 사용하여 SDK의 재시도 횟수를 제한합니다. 선택한 재시도 모드에 따라 제한 예외가 TokenBucket에서 토큰을 뺄 수도 있고 빼지 않을 수도 있습니다.

클라이언트에서 제한 예외 또는 일시적 서버 오류와 같은 재시도 가능한 오류가 발생하면 SDK는 요청을 자동으로 재시도합니다. 재시도 횟수와 속도를 제어할 수 있습니다.

클라이언트를 구성할 때 다음 파라미터를 지원하는 RetryPolicy를 제공할 수 있습니다.

  • numRetries – 요청이 실패한 것으로 간주되기 전에 적용해야 하는 최대 재시도 횟수입니다. 사용하는 재시도 모드와 관계없이 기본값은 8입니다.

    주의

    이 기본값을 변경하려면 신중하게 고려하시기 바랍니다.

  • backoffStrategy - 재시도에 적용할 BackoffStrategy으로, FullJitterBackoffStrategy이 기본 전략입니다. 이 전략은 현재 재시도 횟수, 기본 지연 및 최대 백오프 시간을 기준으로 추가 재시도 사이에 기하급수적 지연을 수행합니다. 그런 다음 지터를 추가하여 약간의 무작위성을 제공합니다. 기하급수적 지연에 사용되는 기본 지연은 재시도 모드와 관계없이 25ms입니다.

  • retryConditionRetryCondition은 요청을 재시도할지 여부를 결정합니다. 기본적으로 재시도 가능하다고 판단되는 특정 HTTP 상태 코드 및 예외 집합을 재시도합니다. 대부분의 경우 기본 구성이면 충분합니다.

다음 코드는 대체 재시도 정책을 제공합니다. 총 5번의 재시도(총 6번의 요청)를 지정합니다. 첫 번째 재시도는 약 100ms 지연 후에 이루어져야 하며, 각 추가 재시도는 최대 1초 지연까지 기하급수적으로 2배 증가해야 합니다.

DynamoDbClient client = DynamoDbClient.builder() .overrideConfiguration(ClientOverrideConfiguration.builder() .retryPolicy(RetryPolicy.builder() .backoffStrategy(FullJitterBackoffStrategy.builder() .baseDelay(Duration.ofMillis(100)) .maxBackoffTime(Duration.ofSeconds(1)) .build()) .numRetries(5) .build()) .build()) .build();

DefaultsMode

ClientOverrideConfigurationRetryMode가 관리하지 않는 제한 시간 속성은 일반적으로 DefaultsMode를 지정하여 암묵적으로 구성됩니다.

AWS SDK for Java 2.x(버전 2.17.102 이상)에 DefaultsMode에 대한 지원이 도입되었습니다. 이 기능은 HTTP 통신 설정, 재시도 동작, 서비스 리전 엔드포인트 설정 및 잠재적인 모든 SDK 관련 구성과 같은 일반적인 구성 가능 설정에 대한 기본값 집합을 제공합니다. 이 기능을 사용하면 일반 사용 시나리오에 맞게 조정된 새 구성 기본값을 얻을 수 있습니다.

기본 모드는 모든 AWS SDK에서 표준화되어 있습니다. SDK for Java 2.x는 다음과 같은 기본 모드를 지원합니다.

  • legacy - AWS SDK에 따라 달라지고 DefaultsMode가 설정되기 전에 존재했던 기본 설정을 제공합니다.

  • standard - 대부분의 시나리오에 최적화되지 않은 기본 설정을 제공합니다.

  • in-region - 표준 모드를 기반으로 구축하며 동일한 AWS 리전에서 AWS 서비스를 직접 호출하는 애플리케이션에 맞게 조정된 설정을 포함합니다.

  • cross-region - 표준 모드를 기반으로 구축하며 동일한 다른 리전에서 AWS 서비스를 직접 호출하는 애플리케이션에 제한 시간이 긴 설정을 포함합니다.

  • mobile - 표준 모드를 기반으로 구축하며 지연 시간이 긴 모바일 애플리케이션에 맞게 조정된 제한 시간이 긴 설정을 포함합니다.

  • auto— 표준 모드를 기반으로 구축하며 실험적 기능을 포함합니다. SDK는 런타임 환경을 검색하여 적절한 설정을 자동으로 결정합니다. 자동 감지는 휴리스틱 기반이며 정확도가 100%는 아닙니다. 런타임 환경을 확인할 수 없는 경우 표준 모드가 사용됩니다. 자동 탐지는 인스턴스 메타데이터와 사용자 데이터를 쿼리할 수 있으며, 이로 인해 지연이 발생할 수 있습니다. 시작 지연 시간이 애플리케이션에 중요한 경우에는 명시적 지연 시간을 DefaultsMode을 대신 선택하는 것이 좋습니다.

다음과 같은 방법으로 기본 모드를 구성할 수 있습니다.

  • AwsClientBuilder.Builder#defaultsMode(DefaultsMode)를 통해 클라이언트에게 직접 전달합니다.

  • defaults_mode 프로필 파일 속성을 통해 구성 프로필에서 구성합니다.

  • aws.defaultsMode 시스템 속성을 통해 전역적으로 구성합니다.

  • AWS_DEFAULTS_MODE 환경 변수를 통해 전역적으로 구성합니다.

참고

legacy 외의 모든 모드에서는 모범 사례가 발전함에 따라 벤딩 기본값이 변경될 수 있습니다. 따라서 legacy 이외의 모드를 사용하는 경우 SDK를 업그레이드할 때 테스트를 수행하는 것이 좋습니다.

AWS SDK 및 도구 참조 안내서의 스마트 구성 기본값은 다양한 기본 모드의 구성 속성 및 기본값 목록을 제공합니다.

애플리케이션의 특성과 애플리케이션이 상호 작용하는 AWS 서비스에 따라 기본 모드 값을 선택합니다.

이러한 값은 다양한 AWS 서비스 선택지를 염두에 두고 구성되었습니다. DynamoDB 테이블과 애플리케이션이 모두 한 리전에 배포되는 일반적인 DynamoDB 배포의 경우 standard 기본 모드 중에서 in-region 기본 모드가 가장 적합합니다.

예 지연 시간이 짧은 직접 호출을 위해 조정된 DynamoDB SDK 클라이언트 구성

다음 예시는 지연 시간이 짧을 것으로 예상되는 DynamoDB 직접 호출의 제한 시간을 더 낮은 값으로 조정합니다.

DynamoDbAsyncClient asyncClient = DynamoDbAsyncClient.builder() .defaultsMode(DefaultsMode.IN_REGION) .httpClientBuilder(AwsCrtAsyncHttpClient.builder()) .overrideConfiguration(ClientOverrideConfiguration.builder() .apiCallTimeout(Duration.ofSeconds(3)) .apiCallAttemptTimeout(Duration.ofMillis(500)) .build()) .build();

개별 HTTP 클라이언트 구현을 통해 제한 시간 및 연결 사용 동작을 훨씬 더 세밀하게 제어할 수 있습니다. 예를 들어, AWS CRT 기반 클라이언트의 경우 클라이언트가 사용된 연결의 상태를 능동적으로 모니터링할 수 있도록 ConnectionHealthConfiguration을 활성화할 수 있습니다. 자세한 내용은 AWS SDK for Java 2.x 개발자 안내서의 AWS CRT 기반 HTTP 클라이언트의 고급 구성을 참조하세요.

연결 유지 구성

연결 유지를 활성화하면 연결을 재사용하여 지연 시간을 줄일 수 있습니다. 연결 유지에는 HTTP 연결 유지와 TCP 연결 유지라는 두 가지 종류가 있습니다.

  • HTTP 연결 유지는 클라이언트와 서버 간의 HTTPS 연결을 유지하려고 시도하므로 이후 요청에서 해당 연결을 재사용할 수 있습니다. 이렇게 하면 이후 요청 시 무거운 HTTPS 인증을 건너뛸 수 있습니다. HTTP 연결 유지는 모든 클라이언트에서 기본적으로 활성화되어 있습니다.

  • TCP 연결 유지는 기본 운영 체제에 소켓 연결을 통해 작은 패킷을 전송하도록 요청하여 소켓의 연결이 유지되어 있는지 확인하고 연결 해제가 발생하면 즉시 감지하도록 합니다. 이렇게 하면 나중에 요청할 때 연결이 해제된 소켓을 사용하느라 시간을 허비하지 않아도 됩니다. TCP 연결 유지는 모든 클라이언트에서 기본적으로 비활성화되어 있습니다. 다음 코드 예제에서는 각 HTTP 클라이언트에서 이를 활성화하는 방법을 보여줍니다. CRT 기반이 아닌 모든 HTTP 클라이언트에 대해 활성화된 경우 실제 연결 유지 메커니즘은 운영 체제에 따라 달라집니다. 따라서 운영 체제를 통해 추가 TCP 연결 유지 값(예: 제한 시간 및 패킷 수)을 구성해야 합니다. Linux 또는 macOS의 sysctl을 사용하거나 Windows의 레지스트리 값을 사용하여 이 작업을 수행할 수 있습니다.

예 Apache 기반 HTTP 클라이언트에서 TCP 연결 유지를 활성화하는 방법
DynamoDbClient client = DynamoDbClient.builder() .httpClientBuilder(ApacheHttpClient.builder().tcpKeepAlive(true)) .build();
URLConnection 기반 HTTP 클라이언트

URLConnection 기반 HTTP 클라이언트 HttpURLConnection을 사용하는 동기식 클라이언트에는 연결 유지를 활성화하는 메커니즘이 없습니다.

예 Netty 기반 HTTP 클라이언트에서 TCP 연결 유지 활성화
DynamoDbAsyncClient client = DynamoDbAsyncClient.builder() .httpClientBuilder(NettyNioAsyncHttpClient.builder().tcpKeepAlive(true)) .build();
예 AWS CRT 기반 HTTP 클라이언트에서 TCP 연결 유지 활성화

AWS CRT 기반 HTTP 클라이언트를 사용하여 TCP 연결 유지를 활성화하고 기간을 제어할 수 있습니다.

DynamoDbClient client = DynamoDbClient.builder() .httpClientBuilder(AwsCrtHttpClient.builder() .tcpKeepAliveConfiguration(TcpKeepAliveConfiguration.builder() .keepAliveInterval(Duration.ofSeconds(50)) .keepAliveTimeout(Duration.ofSeconds(5)) .build())) .build();

비동기식 DynamoDB 클라이언트를 사용하는 경우 다음 코드와 같이 TCP 연결 유지를 활성화할 수 있습니다.

DynamoDbAsyncClient client = DynamoDbAsyncClient.builder() .httpClientBuilder(AwsCrtAsyncHttpClient.builder() .tcpKeepAliveConfiguration(TcpKeepAliveConfiguration.builder() .keepAliveInterval(Duration.ofSeconds(50)) .keepAliveTimeout(Duration.ofSeconds(5)) .build())) .build();

오류 처리

예외 처리와 관련하여 AWS SDK for Java 2.x는 런타임 (확인되지 않은) 예외를 사용합니다.

모든 SDK 예외를 포함하는 기본 예외는 Java 확인되지 않은 RuntimeException에서 확장된 SdkServiceException입니다. 이를 포착하면 SDK에서 발생하는 모든 예외를 포착할 수 있습니다.

SdkServiceException에는 AwsServiceException이라는 하위 클래스가 있습니다. 이 하위 클래스는 AWS 서비스와 통신할 때 문제가 발생했음을 나타냅니다. DynamoDbException이라는 하위 클래스가 있는데, 이는 DynamoDB와의 통신에 문제가 있음을 나타냅니다. 이것을 포착하면 DynamoDB와 관련된 모든 예외를 포착할 수 있지만, 다른 SDK 예외는 포착하지 못합니다.

DynamoDbException 아래에는 더 구체적인 예외 유형이 있습니다. 이러한 예외 유형 중 일부는 TableAlreadyExistsException과 같은 컨트롤 플레인 작업에 적용됩니다. 다른 예외 유형은 데이터 영역 작업에 적용됩니다. 다음은 일반적인 데이터 영역 예외의 예입니다.

  • ConditionalCheckFailedException – 요청에서 false로 평가된 조건을 지정했습니다. 예를 들어 어떤 항목에서 조건부 업데이트 수행을 시도했지만 속성의 실제 값이 조건에서 예상되는 값과 일치하지 않았을 수 있습니다. 이러한 방식으로 실패한 요청은 재시도되지 않습니다.

다른 상황에서는 구체적인 예외가 정의되어 있지 않습니다. 예를 들어 요청이 제한되면 구체적인 ProvisionedThroughputExceededException이 발생하고 다른 경우에는 보다 일반적인 DynamoDbException이 발생할 수 있습니다. 어느 경우에나 isThrottlingException()true를 반환하는지 확인하여 제한으로 인해 예외가 발생했는지 확인할 수 있습니다.

애플리케이션 요구 사항에 따라 모든 AwsServiceException 또는 DynamoDbException 인스턴스를 포착할 수 있습니다. 그러나 상황에 따라 다른 동작이 필요한 경우가 많습니다. 상태 확인 실패를 처리하는 논리는 제한을 처리하는 것과 다릅니다. 처리할 예외적인 경로를 정의하고 대체 경로를 테스트해 보세요. 이를 통해 모든 관련 시나리오를 처리할 수 있습니다.

발생할 수 있는 일반적인 오류 목록은 DynamoDB 관련 오류 처리 섹션을 참조하세요. Amazon DynamoDB API 참조의 Common Errors도 참조하세요. 또한, API 참조는 각 API 작업(예: Query 작업)에서 발생할 수 있는 정확한 오류를 제공합니다. 예외 처리에 대한 자세한 내용은 AWS SDK for Java 2.x 개발자 안내서의 Exception handling for the AWS SDK for Java 2.x를 참조하세요.

AWS 요청 ID

각 요청에는 요청 ID가 포함되어 있으며, 이 ID는 AWS Support과 협력하여 문제를 진단하는 경우 유용하게 사용할 수 있습니다. SdkServiceException에서 파생된 각 예외에는 요청 ID를 검색하는 데 사용할 수 있는 requestId() 메서드가 있습니다.

로깅

SDK에서 제공하는 로깅을 사용하면 클라이언트 라이브러리에서 중요한 메시지를 포착하고 심층적으로 디버깅하는 데 모두 유용할 수 있습니다. 로거는 계층적이며 SDK는 software.amazon.awssdk를 루트 로거로 사용합니다. 수준은 TRACE, DEBUG, INFO, WARN, ERROR, ALL, OFF 중 하나로 구성할 수 있습니다. 구성된 수준은 해당 로거에 적용되며 로거 계층 구조까지 내려갑니다.

AWS SDK for Java 2.x에서는 로깅에 Simple Logging Façade for Java(SLF4J)를 사용합니다. 이는 다른 로거 주변의 추상화 계층 역할을 하며, 이를 사용하여 원하는 로거를 연결할 수 있습니다. 로거 연결에 대한 지침은 SLF4J 사용 설명서를 참조하세요.

각 로거에는 특정한 동작이 있습니다. 기본적으로 Log4j 2.x 로거는 로그 이벤트를 System.out에 추가하고 기본값은 ERROR 로그 수준에 추가하는 ConsoleAppender를 생성합니다.

SLF4J 내에 포함된 SimpleLogger 로거는 기본적으로 System.err을 출력하며 INFO 로그 수준을 기본값으로 사용합니다.

모든 프로덕션 배포에서 출력 수량을 제한하면서 SDK 클라이언트 라이브러리에서 중요한 메시지를 포착하려면 software.amazon.awssdk 수준을 WARN으로 설정하는 것이 좋습니다.

SLF4J가 클래스 경로에서 지원되는 로거를 찾을 수 없는 경우(SLF4J 바인딩 없음) 기본적으로 무작업 구현으로 설정됩니다. 이 구현으로 인해 SLF4J가 클래스 경로에서 로거 구현을 찾을 수 없다는 내용의 메시지가 System.err에 로깅됩니다. 이러한 상황을 방지하려면 로거 구현을 추가해야 합니다. org.slf4j.slf4j-simple 또는 org.apache.logging.log4j.log4j-slf4j2-imp와 같은 아티팩트에 Apache Maven pom.xml의 종속성을 추가하면 됩니다.

애플리케이션 구성에 로깅 종속성을 추가하는 것을 포함하여 SDK에서 로깅을 구성하는 방법에 대한 자세한 내용은 AWS SDK for Java 개발자 안내서의 Logging with the SDK for Java 2.x를 참조하세요.

Log4j2.xml 파일의 다음 구성은 Apache Log4j 2 로거를 사용하는 경우 로깅 동작을 조정하는 방법을 보여줍니다. 이 구성은 루트 로거 수준을 WARN으로 설정합니다. 계층의 모든 로거는 software.amazon.awssdk 로거를 포함하여 이 로그 수준을 상속합니다.

기본적으로 출력은 System.out으로 이동합니다. 다음 예시에서는 여전히 기본 출력 Log4j 어펜더를 재정의하여 맞춤형 Log4j PatternLayout을 적용합니다.

Log4j2.xml 구성 파일 예

다음 구성은 모든 로거 계층 구조에 대해 ERRORWARN 수준의 메시지를 콘솔에 로깅합니다.

<Configuration status="WARN"> <Appenders> <Console name="ConsoleAppender" target="SYSTEM_OUT"> <PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c:%L - %m%n" /> </Console> </Appenders> <Loggers> <Root level="WARN"> <AppenderRef ref="ConsoleAppender"/> </Root> </Loggers> </Configuration>

AWS 요청 ID 로깅

문제가 발생한 경우 예외 내에서 요청 ID를 찾을 수 있습니다. 하지만 예외를 생성하지 않는 요청에 대한 요청 ID를 원하면 로깅을 사용하면 됩니다.

software.amazon.awssdk.request 로거는 DEBUG 수준에서 요청 ID를 출력합니다. 다음 예시는 이전 configuration example를 확장하여 루트 로거 수준을 ERROR로, software.amazon.awssdkWARN 수준으로, software.amazon.awssdk.requestDEBUG 수준으로 유지합니다. 이러한 수준을 설정하면 요청 ID 및 기타 요청 관련 세부 정보(예: 엔드포인트 및 상태 코드)를 파악하는 데 도움이 됩니다.

<Configuration status="WARN"> <Appenders> <Console name="ConsoleAppender" target="SYSTEM_OUT"> <PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c:%L - %m%n" /> </Console> </Appenders> <Loggers> <Root level="ERROR"> <AppenderRef ref="ConsoleAppender"/> </Root> <Logger name="software.amazon.awssdk" level="WARN" /> <Logger name="software.amazon.awssdk.request" level="DEBUG" /> </Loggers> </Configuration>

다음은 로그 출력의 예입니다:

2022-09-23 16:02:08 [main] DEBUG software.amazon.awssdk.request:85 - Sending Request: DefaultSdkHttpFullRequest(httpMethod=POST, protocol=https, host=dynamodb.us-east-1.amazonaws.com, encodedPath=/, headers=[amz-sdk-invocation-id, Content-Length, Content-Type, User-Agent, X-Amz-Target], queryParameters=[]) 2022-09-23 16:02:08 [main] DEBUG software.amazon.awssdk.request:85 - Received successful response: 200, Request ID: QS9DUMME2NHEDH8TGT9N5V53OJVV4KQNSO5AEMVJF66Q9ASUAAJG, Extended Request ID: not available

페이지 매김

QueryScan과 같은 일부 요청의 경우 단일 요청에서 반환되는 데이터 크기가 제한되므로, 후속 페이지를 가져오려면 반복적으로 요청해야 합니다.

Limit 파라미터를 사용하여 각 페이지에 대해 읽을 항목의 최대 수를 제어할 수 있습니다. 예를 들어, Limit 파라미터를 사용하여 마지막 10개 항목만 검색할 수 있습니다. 이 제한은 필터링이 적용되기 전에 테이블에서 읽을 항목 수를 지정합니다. 필터링 후 정확히 10개를 원한다고 해서 지정할 수 있는 방법은 없습니다. 필터링 전의 개수를 제어하고 실제로 10개 항목을 검색한 경우에만 클라이언트 측에서 확인할 수 있습니다. 제한과 관계없이 응답의 최대 크기는 항상 1MB입니다.

API 응답에 LastEvaluatedKey가 포함될 수 있습니다. 이는 개수 제한 또는 크기 제한에 도달하여 응답이 종료되었음을 나타냅니다. 이 키는 해당 응답에 대해 마지막으로 평가된 키입니다. API와 직접 상호 작용하면 이 LastEvaluatedKey를 검색하고 ExclusiveStartKey로 후속 직접 호출에 전달하여 해당 시작 지점부터 다음 청크를 읽을 수 있습니다. LastEvaluatedKey가 반환되지 않으면 Query 또는 Scan API 직접 호출과 일치하는 항목이 더 이상 없는 것입니다.

다음 예시에서는 하위 수준 인터페이스를 사용하여 keyConditionExpression 파라미터에 따라 항목을 100개로 제한합니다.

QueryRequest.Builder queryRequestBuilder = QueryRequest.builder() .expressionAttributeValues(Map.of( ":pk_val", AttributeValue.fromS("123"), ":sk_val", AttributeValue.fromN("1000"))) .keyConditionExpression("pk = :pk_val AND sk > :sk_val") .limit(100) .tableName(TABLE_NAME); while (true) { QueryResponse queryResponse = DYNAMODB_CLIENT.query(queryRequestBuilder.build()); queryResponse.items().forEach(item -> { LOGGER.info("item PK: [" + item.get("pk") + "] and SK: [" + item.get("sk") + "]"); }); if (!queryResponse.hasLastEvaluatedKey()) { break; } queryRequestBuilder.exclusiveStartKey(queryResponse.lastEvaluatedKey()); }

AWS SDK for Java 2.x는 자동으로 다음 결과 페이지를 얻기 위해 여러 서비스 직접 호출을 수행하는 자동 페이지 매김 메서드를 제공함으로써 DynamoDB와의 상호 작용을 단순화할 수 있습니다. 이렇게 하면 코드가 단순해지지만, 페이지를 수동으로 읽으면서 유지할 수 있는 리소스 사용에 대한 일부 제어 기능이 제거됩니다.

DynamoDB 클라이언트에서 사용할 수 있는 QueryPaginatorScanPaginator와 같은 Iterable 메서드를 사용하여 SDK가 페이지 매김을 처리합니다. 이러한 메서드의 반환 유형은 모든 페이지를 반복하는 데 사용할 수 있는 사용자 지정 반복자입니다. SDK는 내부적으로 서비스 직접 호출을 처리합니다. Java Stream API를 사용하여 다음 예제와 같이 QueryPaginator의 결과를 처리할 수 있습니다.

QueryPublisher queryPublisher = DYNAMODB_CLIENT.queryPaginator(QueryRequest.builder() .expressionAttributeValues(Map.of( ":pk_val", AttributeValue.fromS("123"), ":sk_val", AttributeValue.fromN("1000"))) .keyConditionExpression("pk = :pk_val AND sk > :sk_val") .limit(100) .tableName("YourTableName") .build()); queryPublisher.items().subscribe(item -> System.out.println(item.get("itemData"))).join();

데이터 클래스 주석

Java SDK는 데이터 클래스의 속성에 적용할 수 있는 여러 주석을 제공합니다. 이러한 주석은 SDK가 속성과 상호 작용하는 방식에 영향을 줍니다. 주석을 추가하면 속성이 암시적 원자성 카운터 역할을 하도록 하거나, 자동 생성된 타임스탬프 값을 유지하거나, 항목 버전 번호를 추적할 수 있습니다. 자세한 내용은 Data class annotations를 참조하세요.

프라이버시사이트 이용 약관쿠키 기본 설정
© 2025, Amazon Web Services, Inc. 또는 계열사. All rights reserved.