1前書き

/java-couchbase-sdk[Couchbaseの紹介]では、Spring Dataを使用せずにSpringアプリケーションの基本的な永続化レイヤを作成するために一緒に使用できる一連のSpringサービスを作成します。


2クラスタサービス

JVM内でアクティブな

CouchbaseEnvironment

が1つのみであるという制約を満たすために、まずCouchbaseクラスタに接続し、

Cluster

または

CouchbaseEnvironment

インスタンスを直接公開せずにデータバケットへのアクセスを提供するサービスを作成します。


2.1. インタフェース

これが

ClusterService

インターフェースです。

public interface ClusterService {
    Bucket openBucket(String name, String password);
}


2.2. 実装

私たちの実装クラスは

DefaultCouchbaseEnvironment

をインスタンス化し、Springコンテキスト初期化の間の

@ PostConstruct

フェーズの間にクラスタに接続します。

これにより、クラスタはnullではなくなり、クラスが他のサービスクラスにインジェクトされたときに接続されるため、1つ以上のデータバケットを開くことができます。

@Service
public class ClusterServiceImpl implements ClusterService {
    private Cluster cluster;

    @PostConstruct
    private void init() {
        CouchbaseEnvironment env = DefaultCouchbaseEnvironment.create();
        cluster = CouchbaseCluster.create(env, "localhost");
    }
...
}

次に、開いているバケットを格納する

ConcurrentHashMap

を提供し、

openBucket

メソッドを実装します。

private Map<String, Bucket> buckets = new ConcurrentHashMap<>();

@Override
synchronized public Bucket openBucket(String name, String password) {
    if(!buckets.containsKey(name)) {
        Bucket bucket = cluster.openBucket(name, password);
        buckets.put(name, bucket);
    }
    return buckets.get(name);
}


3バケツサービス

アプリケーションの設計方法によっては、複数のSpringサービスで同じデータバケットへのアクセスを提供する必要があります。

アプリケーションの起動時に2つ以上のサービスで同じバケットを開こうとしただけでは、2番目のサービスで

ConcurrentTimeoutException

が発生する可能性があります。

このシナリオを回避するために、バケットごとに

BucketService

インターフェースと実装クラスを定義します。各実装クラスは、

ClusterService

と特定の

Bucket

への直接アクセスが必要なクラスとの間のブリッジとして機能します。


3.1. インタフェース

これが私たちの

BucketService

インターフェースです:

public interface BucketService {
    Bucket getBucket();
}


3.2. 実装

次のクラスは、“

baeldung-tutorial

”バケットへのアクセスを提供します。

@Service
@Qualifier("TutorialBucketService")
public class TutorialBucketService implements BucketService {

    @Autowired
    private ClusterService couchbase;

    private Bucket bucket;

    @PostConstruct
    private void init() {
        bucket = couchbase.openBucket("baeldung-tutorial", "");
    }

    @Override
    public Bucket getBucket() {
        return bucket;
    }
}


TutorialBucketService

実装クラスに

ClusterService

をインジェクトし、

@ PostConstructでアノテーションが付けられたメソッドでバケットを開くことによって、

TutorialBucketService__が他のサービスにインジェクトされたときにバケットが使用できるようになります。


4持続層


Bucket

インスタンスを取得するためのサービスが用意できたので、次に

Bucket

インスタンスを公開せずにエンティティクラスのCRUD操作を他のサービスに提供する、リポジトリに似た永続化レイヤを作成します。


4.1. 個人エンティティ

これが永続化したい

Person

エンティティクラスです。

public class Person {

    private String id;
    private String type;
    private String name;
    private String homeTown;

   //standard getters and setters
}


4.2. JSON

との間のエンティティクラスの変換

Couchbaseがその永続化操作で使用する

JsonDocument

オブジェクトとの間でエンティティクラスを変換するために、

JsonDocumentConverter

インターフェースを定義します。

public interface JsonDocumentConverter<T> {
    JsonDocument toDocument(T t);
    T fromDocument(JsonDocument doc);
}


4.3. JSONコンバーターの実装

次に、

Person

エンティティに

JsonConverter

を実装する必要があります。

@Service
public class PersonDocumentConverter
  implements JsonDocumentConverter<Person> {
    ...
}


JsonObject

クラスの

toJson

および

fromJson

メソッドと一緒に

Jackson

ライブラリを使用して、____エンティティをシリアル化および逆シリアル化することもできますが、追加のオーバーヘッドがあります。

代わりに、

toDocument

メソッドの場合は、

JsonDocument

をラップする前に、

JsonObject

クラスの流暢なメソッドを使用して

JsonObject

を作成してデータを設定します。

@Override
public JsonDocument toDocument(Person p) {
    JsonObject content = JsonObject.empty()
            .put("type", "Person")
            .put("name", p.getName())
            .put("homeTown", p.getHomeTown());
    return JsonDocument.create(p.getId(), content);
}

また、

fromDocument

メソッドには、

fromDocument

メソッドの

Person

クラスの設定メソッドとともに、

JsonObject


クラスの

getString__メソッドを使用します。

@Override
public Person fromDocument(JsonDocument doc) {
    JsonObject content = doc.content();
    Person p = new Person();
    p.setId(doc.id());
    p.setType("Person");
    p.setName(content.getString("name"));
    p.setHomeTown(content.getString("homeTown"));
    return p;
}


4.4. CRUDインターフェース

エンティティクラスの永続化操作を定義する汎用の

CrudService

インターフェースを作成します。

public interface CrudService<T> {
    void create(T t);
    T read(String id);
    T readFromReplica(String id);
    void update(T t);
    void delete(String id);
    boolean exists(String id);
}


4.5. CRUDサービスの実装

entityクラスとconverterクラスが用意されたら、

Person

エンティティに

CrudService

を実装し、上記のバケットサービスとドキュメントコンバータをインジェクトし、初期化中にバケットを取得します。

@Service
public class PersonCrudService implements CrudService<Person> {

    @Autowired
    private TutorialBucketService bucketService;

    @Autowired
    private PersonDocumentConverter converter;

    private Bucket bucket;

    @PostConstruct
    private void init() {
        bucket = bucketService.getBucket();
    }

    @Override
    public void create(Person person) {
        if(person.getId() == null) {
            person.setId(UUID.randomUUID().toString());
        }
        JsonDocument document = converter.toDocument(person);
        bucket.insert(document);
    }

    @Override
    public Person read(String id) {
        JsonDocument doc = bucket.get(id);
        return (doc != null ? converter.fromDocument(doc) : null);
    }

    @Override
    public Person readFromReplica(String id) {
        List<JsonDocument> docs = bucket.getFromReplica(id, ReplicaMode.FIRST);
        return (docs.isEmpty() ? null : converter.fromDocument(docs.get(0)));
    }

    @Override
    public void update(Person person) {
        JsonDocument document = converter.toDocument(person);
        bucket.upsert(document);
    }

    @Override
    public void delete(String id) {
        bucket.remove(id);
    }

    @Override
    public boolean exists(String id) {
        return bucket.exists(id);
    }
}


5すべてを一緒に入れて

これで、パーシスタンス層のすべての部分が整いました。次に、

PersonCrudService

を使用して登録者を保持および取得する登録サービスの簡単な例を示します。

@Service
public class RegistrationService {

    @Autowired
    private PersonCrudService crud;

    public void registerNewPerson(String name, String homeTown) {
        Person person = new Person();
        person.setName(name);
        person.setHomeTown(homeTown);
        crud.create(person);
    }

    public Person findRegistrant(String id) {
        try{
            return crud.read(id);
        }
        catch(CouchbaseException e) {
            return crud.readFromReplica(id);
        }
    }
}


6. 結論

いくつかの基本的なSpringサービスでは、CouchbaseをSpringアプリケーションに組み込み、Spring Dataを使用せずに基本的な永続層を実装することはかなり簡単です。

このチュートリアルに示されているソースコードはhttps://github.com/eugenp/tutorials/tree/master/couchbase[GitHubプロジェクト]にあります。

あなたは公式でCouchbase Java SDKについてもっと学ぶことができます

Couchbase
開発者向けドキュメントサイト。