Couchbase gebruiken in een voorjaarstoepassing

1. Inleiding

In dit vervolg op onze introductie tot Couchbase, creëren we een set Spring-services die samen kunnen worden gebruikt om een ​​basis persistentielaag te creëren voor een Spring-applicatie zonder het gebruik van Spring Data.

2. Clusterservice

Om aan de beperking te voldoen, is dat slechts een enkele Couchbase-omgeving actief kan zijn in de JVM, beginnen we met het schrijven van een service die verbinding maakt met een Couchbase-cluster en toegang biedt tot gegevensbakken zonder de TROS of Couchbase-omgeving gevallen.

2.1. Koppel

Hier is onze ClusterService koppel:

openbare interface ClusterService {Bucket openBucket (Stringnaam, String-wachtwoord); }

2.2. Implementatie

Onze implementatieklasse instantieert een DefaultCouchbaseEnvironment en maakt verbinding met een cluster tijdens de @PostConstruct fase tijdens de initialisatie van de Spring-context.

Dit zorgt ervoor dat het cluster niet nul is en dat het wordt verbonden wanneer de klasse wordt geïnjecteerd in andere serviceklassen, waardoor ze een of meer gegevensbakken kunnen openen:

@Service openbare klasse ClusterServiceImpl implementeert ClusterService {privéclustercluster; @PostConstruct private void init () {CouchbaseEnvironment env = DefaultCouchbaseEnvironment.create (); cluster = CouchbaseCluster.create (env, "localhost"); } ...}

Vervolgens bieden we een ConcurrentHashMap om de open emmers te bevatten en de openBucket methode:

private Map buckets = nieuwe ConcurrentHashMap (); @Override gesynchroniseerde openbare Bucket openBucket (String naam, String wachtwoord) {if (! Buckets.containsKey (naam)) {Bucket bucket = cluster.openBucket (naam, wachtwoord); buckets.put (naam, bucket); } return buckets.get (naam); }

3. Emmer service

Afhankelijk van hoe u uw toepassing ontwerpt, moet u mogelijk toegang verlenen tot dezelfde gegevensbucket in meerdere Spring-services.

Als we slechts hebben geprobeerd dezelfde bucket in twee of meer services te openen tijdens het opstarten van de applicatie, zal de tweede service die dit probeert, waarschijnlijk een ConcurrentTimeoutException.

Om dit scenario te vermijden, definiëren we een BucketService interface en een implementatieklasse per bucket. Elke implementatieklasse fungeert als een brug tussen de ClusterService en de klassen die directe toegang nodig hebben tot een bepaald Emmer.

3.1. Koppel

Hier is onze BucketService koppel:

openbare interface BucketService {Bucket getBucket (); }

3.2. Implementatie

De volgende klasse biedt toegang tot de “baeldung-tutorial" emmer:

@Service @Qualifier ("TutorialBucketService") openbare klasse TutorialBucketService implementeert BucketService {@Autowired privé ClusterService couchbase; privé emmer; @PostConstruct private void init () {bucket = couchbase.openBucket ("baeldung-tutorial", ""); } @Override public Bucket getBucket () {return bucket; }}

Door de ClusterService in onze TutorialBucketService implementatieklasse en het openen van de bucket in een methode die is geannoteerd met @PostConstruct, we hebben ervoor gezorgd dat de emmer klaar is voor gebruik wanneer de TutorialBucketService wordt vervolgens in andere services geïnjecteerd.

4. Persistentielaag

Nu we een service hebben om een Emmer we zullen bijvoorbeeld een repository-achtige persistentielaag maken die CRUD-bewerkingen biedt voor entiteitsklassen voor andere services zonder de Emmer instantie voor hen.

4.1. De persoonsentiteit

Hier is de Persoon entiteitsklasse die we willen behouden:

openbare klasse Persoon {privé String-id; privé String-type; private String naam; privé String homeTown; // standaard getters en setters}

4.2. Entiteitsklassen van en naar JSON converteren

Om entiteitsklassen van en naar het JsonDocument objecten die Couchbase gebruikt in zijn persistentiebewerkingen, definiëren we de JsonDocumentConverter koppel:

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

4.3. Implementatie van de JSON-converter

Vervolgens moeten we een JsonConverter voor Persoon entiteiten.

@Service openbare klasse PersonDocumentConverter implementeert JsonDocumentConverter {...}

We kunnen de Jackson bibliotheek in combinatie met de JsonObject klas naar Json en van Json methoden om hetentiteiten, maar er is wel extra overhead aan verbonden.

In plaats daarvan voor de documenteren methode gebruiken we de vloeiende methoden van de JsonObject klasse om een JsonObject alvorens het in te pakken a JsonDocument:

@ Openbare JsonDocument overschrijven naarDocument (Persoon p) {JsonObject content = JsonObject.empty () .put ("type", "Persoon") .put ("naam", p.getName ()) .put ("homeTown", p .getHomeTown ()); retourneer JsonDocument.create (p.getId (), content); }

En voor de vanDocument methode gebruiken we deJsonObject klas getString methode samen met de setters in de Persoon klas in onze vanDocument methode:

@Override publieke persoon fromDocument (JsonDocument doc) {JsonObject content = doc.content (); Persoon p = nieuwe persoon (); p.setId (doc.id ()); p.setType ("Persoon"); p.setName (content.getString ("naam")); p.setHomeTown (content.getString ("homeTown")); terug p; }

4.4. CRUD-interface

We maken nu een generiek CrudService interface die persistentiebewerkingen voor entiteitsklassen definieert:

openbare interface CrudService {void create (T t); T lezen (String-id); T readFromReplica (String-id); ongeldige update (T t); ongeldig verwijderen (String-id); boolean bestaat (String-id); }

4.5. Implementatie van de CRUD-service

Nu de entiteit- en converterklassen aanwezig zijn, implementeren we nu de CrudService voor de Persoon entiteit, waarbij de hierboven getoonde bucket-service en documentconverter wordt geïnjecteerd en de bucket wordt opgehaald tijdens de initialisatie:

@Service openbare klasse PersonCrudService implementeert CrudService {@Autowired privé TutorialBucketService bucketService; @Autowired privé PersonDocumentConverter-omzetter; privé emmer; @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 (persoon); bucket.insert (document); } @Override public Person read (String id) {JsonDocument doc = bucket.get (id); return (doc! = null? converter.fromDocument (doc): null); } @Override publieke persoon readFromReplica (String id) {List docs = bucket.getFromReplica (id, ReplicaMode.FIRST); return (docs.isEmpty ()? null: converter.fromDocument (docs.get (0))); } @Override openbare ongeldige update (Persoon persoon) {JsonDocument document = converter.toDocument (persoon); bucket.upsert (document); } @Override public void delete (String id) {bucket.remove (id); } @Override public boolean bestaat (String id) {return bucket.exists (id); }}

5. Alles samenvoegen

Nu we alle onderdelen van onze persistentielaag hebben, is hier een eenvoudig voorbeeld van een registratiedienst die de PersonCrudService om houders aan te houden en op te halen:

@Service openbare klasse RegistrationService {@Autowired private PersonCrudService crud; public void registerNewPerson (String naam, String homeTown) {Persoon person = nieuwe persoon (); person.setName (naam); person.setHomeTown (thuistad); crud.create (persoon); } openbare persoon findRegistrant (String id) {probeer {return crud.read (id); } catch (CouchbaseException e) {return crud.readFromReplica (id); }}}

6. Conclusie

We hebben laten zien dat het met een paar standaard Spring-services vrij triviaal is om Couchbase op te nemen in een Spring-applicatie en een basis persistentielaag te implementeren zonder Spring Data te gebruiken.

De broncode die in deze tutorial wordt getoond, is beschikbaar in het GitHub-project.

U kunt meer te weten komen over de Couchbase Java SDK op de officiële Couchbase ontwikkelaarsdocumentatiesite.