Spring Data DynamoDBでSpringからDynamoDBにアクセスする

spring

はじめに

Spring BootからDynamoDBにアクセスする際、まず考えるのがAWS SDK for Javaを使うことだと思います(少なくとも私はそうでした)。ですが、もう少しSpringと親和性が高い方法もあるのではないかと思い調べたところSpring Data DynamoDBを見つけました。今回はこのライブラリの使用方法について書きたいと思います。

手順について

ではライブラリの使用手順についてです。Spring Data DynamoDBの使用例をベースとしておりますが

  • AWSのアクセスキー・シークレットキーをクレデンシャルより取得するようにした
  • CRUDを全て試したみた

などを変更しております。

1.DynamoDBの準備

まずは今回データを登録するDynamoDBをAWS上に作成します。AWSコンソール上で以下のようにテーブルを作成しました。

  • テーブル名 ・・・ SpringUser
  • プライマリキー ・・・ id

2.build.gradle

以降はプログラムについてです。今回はGradleを使用したのでbuild.gradleに以下のように記述しました。

buildscript {
	ext {
		springBootVersion = '1.3.5.RELEASE'
	}
	repositories {
		mavenCentral()
	}
	dependencies {
		classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 
	}
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'spring-boot' 

jar {
	baseName = 'SpringBootDynamoDBSample'
	version = '0.0.1-SNAPSHOT'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
	mavenCentral()
}


dependencies {
	compile('org.springframework.boot:spring-boot-starter')
	compile group: 'com.github.derjust', name: 'spring-data-dynamodb', version: '4.2.3'
	testCompile('org.springframework.boot:spring-boot-starter-test') 
}


eclipse {
	classpath {
		 containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')
		 containers 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8'
	}
}

build.gradleのベースはSpring Initializrで作成したプロジェクトのものです。これに「spring-data-dynamodb」を追加しました(31行目)。

3.SpringUserクラス

DynamoDBに作成したSpringDataテーブルに対応するクラスです。idの他にfirstName、lastNameを属性として持たせました。

SpringUser.java
package com.example;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAutoGeneratedKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;

@DynamoDBTable(tableName = "SpringUser")
public class SpringUser {
    
    private String id;
    private String firstName;
    private String lastName;
    
    public SpringUser(){
        
    }
    
    public SpringUser(String firstName, String lastName){
        this.firstName = firstName;
        this.lastName = lastName;
    }
    
    @DynamoDBHashKey
    @DynamoDBAutoGeneratedKey 
    public String getId()
    {
      return id;
    }

    @DynamoDBAttribute
    public String getFirstName()
    {
      return firstName;
    }

    @DynamoDBAttribute
    public String getLastName()
    {
      return lastName;
    }
    
    public void setId(String id){
        this.id = id;
    }
    
    public void setFirstName(String firstName){
        this.firstName = firstName;
    }
    
    public void setLastName(String lastName){
        this.lastName = lastName;
    }
}

クラス名には「@DynamoDBTable」アノテーションで対応するテーブル名を、Getterにもそれぞれ対応するアノテーションを付与しています。

4.SpringUserRepositoryクラス

データを操作するためのリポジトリです。以下のようになります。

SpringUserRepository.java
package com.example.repositories;

import java.util.List;

import org.socialsignin.spring.data.dynamodb.repository.EnableScan;
import org.springframework.data.repository.CrudRepository;

import com.example.SpringUser;

@EnableScan
public interface SpringUserRepository extends CrudRepository<SpringUser, String> {
  List<SpringUser> findByLastName(String lastName);
}

5.DynamoDBConfigクラスとapplication.yml

DynamoDBへの接続を定義するDynamoDBConfigクラスと、定義ファイルであるapplication.ymlです。先にも書いたようにDynamoDBConfigクラスでは、AWSのアクセスキー・シークレットキーをアプリ内で保持せず、クレデンシャル(~/.aws/credentialsなど)から取得するようにしました。

DynamoDBConfig.java
package com.example;

import org.socialsignin.spring.data.dynamodb.repository.config.EnableDynamoDBRepositories;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;

@Configuration
@EnableDynamoDBRepositories(basePackages = "com.example.repositories")
public class DynamoDBConfig {
    @Value("${amazon.dynamodb.endpoint}")
    private String amazonDynamoDBEndpoint;
    
    @Value("${amazon.credential.profile}")
    private String profile;

    @Bean
    public AmazonDynamoDB amazonDynamoDB() {
        AmazonDynamoDB amazonDynamoDB = new AmazonDynamoDBClient(amazonAWSCredentials());
        if (!StringUtils.isEmpty(amazonDynamoDBEndpoint)) {
            amazonDynamoDB.setEndpoint(amazonDynamoDBEndpoint);
        }
        return amazonDynamoDB;
    }

    @Bean
    public AWSCredentials amazonAWSCredentials() {
        return new ProfileCredentialsProvider(profile).getCredentials();
    }
}
application.yml
amazon:
  dynamodb:
    endpoint: https://dynamodb.ap-northeast-1.amazonaws.com
  credential:
    profile: default

DynamoDBConfigクラスはapplication.yml内の定義値(endpoint、profile)を読み取って使用しています。application.ymlのprofileについては、クレデンシャル(~/.aws/credentialsなど)に定義した任意のプロファイル名としてください。

6.Applicationクラス

最後に、ここまで書いたクラスを利用するApplicationクラスです。DynamoDBにデータを登録し、抽出・更新・削除を行います。

Application.java
package com.example;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

import com.example.repositories.SpringUserRepository;

@SpringBootApplication
public class Application {

    @Autowired
    private SpringUserRepository repository;
    
	public static void main(String[] args) {
	    try (ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args)) {
            Application app = ctx.getBean(Application.class);
            app.run(args);
        } catch (Exception e) {
            e.printStackTrace();
        }
	}
	
	public void run(String... args) throws Exception {
        System.out.println("処理開始");
        
        SpringUser taro = new SpringUser("taro", "yamada");
        repository.save(taro);
        
        SpringUser jiro = new SpringUser("jiro", "yamada");
        repository.save(jiro);
        
        SpringUser saburo = new SpringUser("saburo", "yamada");
        repository.save(saburo);
        
        SpringUser takeshi = new SpringUser("takeshi", "suzuki");
        repository.save(takeshi);
        
        List<SpringUser> result = repository.findByLastName("yamada");
        for(SpringUser user : result){
            System.out.println(user.getFirstName() + " " + user.getLastName());
        }
        
        jiro.setLastName("tanaka");
        repository.save(jiro);
        
        repository.delete(saburo);
        
        System.out.println("処理終了");
    }
}

まとめ

Spring Data DynamoDBを使い、CRUDができることが確認できました。リポジトリを通してデータの更新を行うところなどが、DynamoDB固有の処理を上手く隠蔽化しているのではと感じます。何かの時に参考になれば幸いです。