Рубрики
Без рубрики

Использование Couchbase в весеннем приложении

Создайте слой персистентности в приложении Spring с помощью Couchbase.

Автор оригинала: baeldung.

1. введение

В этом дополнении к нашему введению в Couchbase мы создаем набор служб Spring , которые можно использовать вместе для создания базового уровня сохраняемости для приложения Spring без использования данных Spring.

2. Служба кластеров

Чтобы удовлетворить ограничению, согласно которому в JVM может быть активна только одна среда CouchbaseEnvironment , мы начинаем с написания службы, которая подключается к кластеру Couchbase и предоставляет доступ к ведрам данных без непосредственного доступа к экземплярам Cluster или CouchbaseEnvironment .

2.1. Интерфейс

Вот наш Кластерный сервис интерфейс:

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

2.2. Реализация

Наш класс реализации создает экземпляр DefaultCouchbaseEnvironment и подключается к кластеру во время фазы @PostConstruct во время инициализации контекста Spring.

Это гарантирует, что кластер не является нулевым и что он подключен, когда класс вводится в другие классы обслуживания, что позволяет им открывать один или несколько сегментов данных:

@Service
public class ClusterServiceImpl implements ClusterService {
    private Cluster cluster;
    
    @PostConstruct
    private void init() {
        CouchbaseEnvironment env = DefaultCouchbaseEnvironment.create();
        cluster = CouchbaseCluster.create(env, "localhost");
    }
...
}

Затем мы предоставляем ConcurrentHashMap , чтобы содержать открытые ведра и реализовать метод open Bucket :

private Map 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.

Если мы просто попытаемся открыть одно и то же ведро в двух или более службах во время запуска приложения, вторая служба, которая попытается это сделать, скорее всего, столкнется с ConcurrentTimeoutException .

Чтобы избежать этого сценария, мы определяем Bucket Service interface и класс реализации для каждого bucket. Каждый класс реализации действует как мост между Службой кластеров и классами, которым необходим прямой доступ к определенному ведру .

3.1. Интерфейс

Вот наш Сервис ведра интерфейс:

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;
    }
}

Введя службу Cluster Service в наш класс реализации TutorialBucket Service и открыв ведро в методе, аннотированном @PostConstruct, мы обеспечили, что ведро будет готово к использованию, когда TutorialBucketService затем будет введено в другие службы.

4. Уровень персистентности

Теперь, когда у нас есть служба для получения экземпляра Bucket , мы создадим похожий на репозиторий уровень сохраняемости, который предоставляет операции CRUD для классов сущностей другим службам, не предоставляя им экземпляр Bucket .

4.1. Физическое Лицо

Вот класс Person entity, который мы хотим сохранить:

public class Person {

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

    // standard getters and setters
}

4.2. Преобразование Классов Сущностей В JSON и из Него

Чтобы преобразовать классы сущностей в объекты Json Document , которые Couchbase использует в своих операциях сохранения, мы определяем интерфейс JsonDocumentConverter :

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

4.3. Реализация конвертера JSON

Далее нам нужно реализовать JsonConverter для Person entities.

@Service
public class PersonDocumentConverter
  implements JsonDocumentConverter {
    ...
}

Мы могли бы использовать библиотеку Jackson в сочетании с методами JSONObject класса toJSON и FromJSON для сериализации и десериализации сущностей |, однако при этом возникают дополнительные накладные расходы.

Вместо этого для метода to Document мы будем использовать методы fluent класса JSONObject для создания и заполнения JSONObject перед тем, как обернуть его в JsonDocument :

@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);
}

А для метода from Document мы будем использовать метод JSONObject класса getString вместе с установщиками в классе Person в нашем методе fromDocument :

@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

Теперь мы создаем универсальный Crud-сервис интерфейс, который определяет операции сохранения для классов сущностей:

public interface CrudService {
    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 на месте, мы теперь реализуем службу Crud для Person entity, вводя службу bucket и конвертер документов, показанные выше, и извлекая ведро во время инициализации:

@Service
public class PersonCrudService implements CrudService {
    
    @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 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.

Исходный код, показанный в этом руководстве, доступен в проекте GitHub .

Вы можете узнать больше о Java SDK Couchbase на официальном сайте документации разработчика Couchbase.