Couchbase – How to create Spring Cache Couchbase application with SpringBoot

Performance is a big problem in software development. And Caching is one solution to speed up system. In the past post, We are familiar with Couchbase database by learning how to build Spring JPA Couchbase application. So in the tutorial, JavaSampleApproach will continue to show you how to create Spring Cache Couchbase application with SpringBoot.

Related posts:
How to work with Spring Cache | Spring Boot
Couchbase – How to create Spring JPA Couchbase application with SpringBoot
SpringBoot Caffeine cache with PostgreSQL backend
SpringBoot Hazelcast cache with PostgreSQL backend

I. Technologies

– Java 1.8
– Maven 3.3.9
– Spring Tool Suite – Version 3.8.1.RELEASE
– Spring Boot: 1.5.6RELEASE
– Couchbase 4.6.2

II. Spring Cache Couchbase

We can use Couchbase as backing cache:

spring cache couchbase - architecture

For work with SpringCache Couchbase, we need a dependency:


	com.couchbase.client
	couchbase-spring-cache

How to configure Couchbase server as Cache?
-> We need to build a CacheManager with Couchbase cluster:

@EnableCaching
@Configuration
public class CacheConfig {

    ...
	
    @Bean(destroyMethod = "disconnect")
    public Cluster cluster() {
        return CouchbaseCluster.create(couchbaseServer);
    }

    @Bean(destroyMethod = "close")
    public Bucket bucket() {
        return cluster().openBucket(couchbaseBucket, couchbasePassword);
    }

    @Bean
    public CacheManager cacheManager() {
        CacheBuilder cacheBuilder = CacheBuilder.newInstance(bucket()).withExpiration(0);
        return new CouchbaseCacheManager(cacheBuilder, CACHE_NAME);
    }

}

@EnableCaching is used to enable the caching.

Document for Couchbase cache is built with Serializable:

public class Customer implements Serializable {
...

}

We use SpringCache annotations to define the ways for caching with each operation {@Cacheable, @CachePut, @CacheEvict}:

@Cacheable is one of the most important and common annotation for caching the requests. If the application sends multiple requests, this annotation will not execute the method which is Cachable multiple times, instead it will return the result from the cached storage.
@CachePut updates the cache which is stored and execute the method.
@CacheEvict is used for removing a single cache or clearing the entire cache from the cache storage. The method evict uses the input parameter id as a key to find the object that has the same id and removes it from the cache.

III. Practice

In the tutorial, we create a SpringBoot project as below:

spring cache couchbase - project structure

Step to do:
– Create SpringBoot project
– Create model class
– Configure Couchbase cache
– Implement repository
– Implement cache service
– Implement business service
– Create Restful APIs
– Deployment

1. Create SpringBoot project

Using SpringToolSuite to create a SpringBoot project, then add dependencies {pring-boot-starter-web, couchbase-spring-cache}:


	org.springframework.boot
	spring-boot-starter-web



	com.couchbase.client
	couchbase-spring-cache

2. Create model class

– Create a Customer model:

package com.javasampleapproach.couchbase.model;

import java.io.Serializable;
 
public class Customer implements Serializable {
	private static final long serialVersionUID = 1L;

	private String id;
 
	private String firstName;
 
	private String lastName;
	
	public Customer(String id, String firstName, String lastName){
		this.id = id;
		this.firstName = firstName;
		this.lastName = lastName;
	}
	
	public String getId() {
		return this.id;
	}
 
	public void setId(String id) {
		this.id = id;
	}
 
	public String getFirstName() {
		return this.firstName;
	}
 
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
 
	public String getLastName() {
		return this.lastName;
	}
 
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
 
	@Override
	public String toString() {
		return String.format("Customer[ id=%s, firstName=%s, lastName=%s]", this.id, this.firstName, this.lastName);
	}
}

3. Configure Couchbase cache

Open application.properties file, configure Couchbase server:

jsa.couchbase.server=127.0.0.1
jsa.couchbase.bucket=jsabucket
jsa.couchbase.password=123456

Then configure CacheManager:

package com.javasampleapproach.couchbase.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.Cluster;
import com.couchbase.client.java.CouchbaseCluster;
import com.couchbase.client.spring.cache.CacheBuilder;
import com.couchbase.client.spring.cache.CouchbaseCacheManager;

@EnableCaching
@Configuration
public class CacheConfig {

    public static final String CACHE_NAME = "customers";
    
	@Value("${jsa.couchbase.server}")
    private String couchbaseServer;
	
	@Value("${jsa.couchbase.bucket}")
	private String couchbaseBucket;
	
	@Value("${jsa.couchbase.password}")
	private String couchbasePassword;

    @Bean(destroyMethod = "disconnect")
    public Cluster cluster() {
        // connect to the Couchbase server running on your local machine
        return CouchbaseCluster.create(couchbaseServer);
    }

    @Bean(destroyMethod = "close")
    public Bucket bucket() {
        // connect to the bucket named 'jsabucket' (which must exist on your Couchbase server)
        // every cache related element will use this bucket
        return cluster().openBucket(couchbaseBucket, couchbasePassword);
    }

    @Bean
    public CacheManager cacheManager() {
        CacheBuilder cacheBuilder = CacheBuilder.newInstance(bucket()).withExpiration(0);
        return new CouchbaseCacheManager(cacheBuilder, CACHE_NAME);
    }

}
4. Implement repository

– Create an interface CustomerRepository:

package com.javasampleapproach.couchbase.repo;

import com.javasampleapproach.couchbase.model.Customer;

public interface CustomerRepository {
	public Customer getById(long id);
	public Customer put(String firstName, long id);
}

– Implement above CustomerRepository:

package com.javasampleapproach.couchbase.repo.impl;

import java.util.HashMap;
import java.util.Map;

import org.springframework.stereotype.Repository;

import com.javasampleapproach.couchbase.model.Customer;
import com.javasampleapproach.couchbase.repo.CustomerRepository;

@Repository
public class CustomerRepositoryImpl implements CustomerRepository{
	
	private static Map store = new HashMap();
    static{
        store.put(1L, new Customer("1", "Jack", "Smith"));
        store.put(2L, new Customer("2", "Adam", "Johnson"));
    }

	@Override
	public Customer getById(long id) {
		System.out.println("Service processing...");
		
		// provide a delay time for simulating slowly processing
        try{
            Thread.sleep(3000); 
        }catch(Exception e){
        }
        
		Customer cust = store.get(id);
        return cust;
	}

	@Override
	public Customer put(String firstName, long id) {
		Customer cust = store.get(id);
		cust.setFirstName(firstName);
		
		return cust;
	}
}

5. Implement cache service

Using SpringCache annotations to implement CustomerCache:

package com.javasampleapproach.couchbase.service.cache;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;

import com.javasampleapproach.couchbase.config.CacheConfig;
import com.javasampleapproach.couchbase.model.Customer;
import com.javasampleapproach.couchbase.repo.CustomerRepository;

@Component
public class CustomerCache {
	
	@Autowired
	CustomerRepository customerRepository;
	
	@CachePut(value=CacheConfig.CACHE_NAME, key="#id")
    public Customer putOnCache(String firstName, long id){
        return customerRepository.put(firstName, id);
    }
     
    @Cacheable(value=CacheConfig.CACHE_NAME, key="#id")
    public Customer getOnCache(long id){
    	return customerRepository.getById(id);
    }
     
    @CacheEvict(value = CacheConfig.CACHE_NAME, key = "#id")
    public void evict(long id){
    }
}
6. Implement business service

Implement CustomerServices on top of above CustomerCache:

package com.javasampleapproach.couchbase.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.javasampleapproach.couchbase.model.Customer;
import com.javasampleapproach.couchbase.service.cache.CustomerCache;

@Service
public class CustomerServices {
	
	@Autowired
	CustomerCache customerCache;
	
    public Customer putCustomer(String firstName, long id){
        return customerCache.putOnCache(firstName, id);
    }
     
    public Customer get(long id){
    	return customerCache.getOnCache(id);
    }
     
    public void evict(long id){
    	customerCache.evict(id);
    }
}

7. Create Restful APIs

Create 3 RestAPIs {/cachable, /cacheput, /cacheevict}:

package com.javasampleapproach.couchbase.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.javasampleapproach.couchbase.model.Customer;
import com.javasampleapproach.couchbase.service.CustomerServices;

@RestController
public class WebController {
     
    @Autowired
    CustomerServices service;
     
    @RequestMapping("/cachable")
    public Customer get(@RequestParam("id")long id){
        return service.get(id);
    }
    
    @RequestMapping("/cacheput")
    public String put(@RequestParam("firstname") String firstName, @RequestParam("id")long id){
        service.putCustomer(firstName, id);
        return "Done";
    }
     
    @RequestMapping("/cacheevict")
    public String evict(@RequestParam("id")long id){
        service.evict(id);
        return "Done";
    }
     
}
8. Deployment
8.1 Setup Couchbase server

Follow the guide to setup Couchbase server and create a jsabucket

8.2 Run and check results

Check document in jsabucket before run above SpringBoot project.

Build and Run the SpringBoot project as commanlines {mvn clean install, mvn spring-boot:run}.
Request 1: http://localhost:8080/cachable?id=1
-> Results:
Service process slowly and,

spring cache couchbase - cacheable request 1

Server has displayed a text on console:

Service processing...

Check documents of Couchebase jsabucket:

spring cache couchbase - cacheable request 1 - couche document

Request 2: http://localhost:8080/cachable?id=1
Now the response is faster because Customer with id = 1 has been cached before, the application just get data from cache storage.

spring cache couchbase - cacheable request 1

Request 3: http://localhost:8080/cacheput?id=1&firstname=Peter
Message is returned on Browser:
Done
Now customer with id=1 is modified: firstname=”Peter”, not “Jack”.

Request 4: http://localhost:8080/cachable?id=1
Response is faster BUT the result is difference from first request:

spring cache couchbase - cacheable request 4

Request 5 – Make a cache-evict request: http://localhost:8080/cacheevict?id=1
Browser displays:
Done
Now customer with id=1 was evicted from cache storage.

spring cache couchbase - jsabucket - no document

Request 6: http://localhost:8080/cachable?id=1
Now the behavior of the browser is the same as the first request because customer with id=1 was evicted to cache, and the method under @Cachable is executed.
Service process slowly and result:

spring cache couchbase - cacheable request 4

Server, of course, displays a text on console:

Service processing...

spring cache couchbase - cacheable request 1 - couche document

IV. Sourcecode

SpringCacheCouchbase



By grokonez | August 24, 2017.


Related Posts


Got Something To Say:

Your email address will not be published. Required fields are marked *

*