아장아장 개발 일기

Spring + Local DynamoDB 본문

개발/AWS

Spring + Local DynamoDB

빨간머리 마녀 🍒 2022. 5. 4. 11:26

Spring Gradle에서 Local DynamoDB configuration 하기

이번 포트에서는 스프링에서 Local DynamoDB를 세팅 후 User 테이블에 아이템을 등록하는 테스트를 하려 합니다.

 

먼저 아래의 세 개 의존성을 주입합니다.(맨 아래 baeldung 소스 참고함)

build.gradle

dependencies{
		...
    implementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.205'
    implementation 'org.springframework.data:spring-data-releasetrain:Lovelace-RELEASE'
    implementation 'com.github.derjust:spring-data-dynamodb:5.1.0'
		...
}



properties 파일에 로컬 DynamoDB의 엔드포인트인 ‘http://localhost:8000/’와 본인의 aws 액세스 키와 시크릿 키를 입력합니다.

 

이는 아래 configuration 클래스에서 가져다 dynamoDB를 세팅하는데 사용됩니다.

properties

amazon.dynamodb.endpoint=http://localhost:8000/
amazon.aws.accesskey=key
amazon.aws.secretkey=key2



아래는 properties 파일의 aws 엔드포인트, 액세스키, 시크릿키 정보를 활용해 AmazonDynamoDB, DynamoDB 클래스를 빈으로 등록 하는 소스입니다.

 

여기서 등록된 빈들은 이후 테스트 코드에서 활용됩니다. 각 코드 블럭에 대한 설명은 주석 참고 부탁 드립니다.

Configuration 클래스

@Configuration
@PropertySource("classpath:aws.properties")
@EnableDynamoDBRepositories(basePackages = "com.example.dynamodbtest.repository")
public class DynamoDBConfig {
    @Value("${aws.dynamodb.endpoint}")
    private String amazonDynamoDBEndpoint;
    
    @Value("${aws.accessKey}")
    private String amazonAWSAccessKey;
    
    @Value("${aws.secretKey}")
    private String amazonAWSSecretKey;
    
    @Value("${region}")
    private String region;
    
    @Bean
    public AmazonDynamoDB amazonDynamoDB() {
        // aws 엔드포인트 설정. 
        // 따로 설정하지 않을시에는 디폴트 주소로 연결됨
        // (<https://dynamodb.ap-northeast-2.amazonaws.com>)
        AwsClientBuilder.EndpointConfiguration endpointConfiguration = 
                new AwsClientBuilder.EndpointConfiguration(amazonDynamoDBEndpoint, region);
    
        // AWSCredentials 및 엔드포인트 설정
        return AmazonDynamoDBClientBuilder.standard()
                .withCredentials(new AWSStaticCredentialsProvider(amazonAWSCredentials()))
                .withEndpointConfiguration(endpointConfiguration)
                .build();
    }
    
    @Bean
    public DynamoDB dynamoDB() {
        return new DynamoDB(amazonDynamoDB());
    }
    
    @Bean
    public AWSCredentials amazonAWSCredentials() {
        return new BasicAWSCredentials(
                amazonAWSAccessKey, amazonAWSSecretKey);
    }
}



테이블 생성 및 테스트를 진행할 도메인 클래스입니다.

Domain 클래스

@AllArgsConstructor
@NoArgsConstructor
@DynamoDBTable(tableName = "User")        // 클래스를 DynamoDB 테이블로 표시하는 어노테이션
public class User {

    private String id;

    private String username;

    private String password;

    private String email;

    private String role;

    // property를 해쉬키로 등록하는 어노테이션. getter나 클래스 필드에 적용됨.
    // 클래스 필드에 적용하는 경우 getter, setter가 같은 클래스 내에 선언되어야함.
    // 필수 어노테이션
    @DynamoDBHashKey
    // 해쉬키 혹은 레인지 키 특성을 지정하기 위한 어노테이션으로 UUID 키가 자동 생성됨.
    // String 타입의 키만 자동 생성 가능.(다른 타입에 해당 어노테이션을 적용하면 타입 오류 발생)
    // 역시나 클래스 필드에 적용하는 경우 getter, setter가 같은 클래스 내에 선언되어야함.
    @DynamoDBAutoGeneratedKey
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    // 테이블의 attribute로 지정하는 어노테이션. 
    // 클래스의 property 명이 테이블의 attribute 명과 일치하면 옵션으로 사용 가능.
    // 다를경우 @DynamoDBAttribute(attributeName = "username") 와 같이 표시 필요.
    @DynamoDBAttribute
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @DynamoDBAttribute
    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @DynamoDBAttribute
    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @DynamoDBAttribute
    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }

}

 

마지막으로 테이블을 생성하고, 해당 테이블에 User 아이템을 등록 후, 테이블을 삭제하는 테스트 코드입니다.

 

코드를 잘 보시면, 테이블을 생성하고 삭제할 때 해당 동작이 완성될 때까지 기다리는 코드가 있습니다.(waitForActive(), waitForDelete())

 

해당 코드 없이 테스트를 진행하면 테이블 생성과 삭제가 완료되기 전에 다음 코드가 실행돼서 Resources Not Found 오류가 발생하니 안정적인 테스트 진행을 위해 해당 코드가 꼭 필요해 보입니다.

Test 클래스

@SpringBootTest(classes = DynamoDbTestApplication.class)
@WebAppConfiguration
class UserRepositoryTest {
    
    @Autowired
    private DynamoDB dynamoDB;
    
    @Autowired
    private AmazonDynamoDB amazonDynamoDB;
    
    @Autowired
    private UserRepository repository;
    
    private final Class<User> tableClass = User.class;
    
    private Table table;
    
    private String tableName;
    
    @BeforeEach
    public void 테이블_생성() {
        try {
            DynamoDBMapper dynamoDBMapper = new DynamoDBMapper(amazonDynamoDB);
            CreateTableRequest tableRequest = dynamoDBMapper.generateCreateTableRequest(tableClass);
            tableRequest.setProvisionedThroughput(new ProvisionedThroughput(1L, 1L));
            
            table = dynamoDB.createTable(tableRequest);
            tableName = table.getTableName();
            System.out.println(tableName + " 테이블을 생성중입니다. 다소 시간이 걸릴 수 있습니다.");
            table.waitForActive();
        }
        catch (InterruptedException e) {
            System.err.println(tableName + " 테이블 생성 요청에 실패했습니다.");
        }
    }
    
    @AfterEach
    void 테이블_삭제() {
        try {
            Table table = dynamoDB.getTable(tableName);
            table.delete();
            System.out.println(tableName + " 테이블 삭제 요청중입니다. 다소 시간이 걸릴 수 있습니다.");
            table.waitForDelete();
        }
        catch (InterruptedException e) {
            System.err.println(tableName + " 테이블 삭제요청에 실패했습니다.");
        }
    }

    @Test
    public void 유저_등록() {
        User user = new User();
        user.setUsername("test");
        user.setEmail("test@test.com");
        user.setPassword("test");
        user.setRole("USER");
        
        repository.save(user);
    
        Iterable<User> all = repository.findAll();
        for (User u : all) {
            String id = u.getId();
            String username = u.getUsername();
            String role = u.getRole();
            System.out.println("id = " + id);
            System.out.println("username = " + username);
            System.out.println("role = " + role);
        }
    }
}



테스트를 실행하기 전, cmd에서 http://localhost:8000을 실행시킵니다.

 

  1. dynamoDB 로컬 폴더가 설치된 위치로 이동합니다.
  2. 아래 명령문을 입력합니다.
    • java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb


테스트 결과

>> 참고

https://www.baeldung.com/spring-data-dynamodb

https://stackoverflow.com/questions/33801460/dynamo-db-local-connection-refused

Comments