Spring Boot Couchbase Caching Example Configuration
Couchbase is a NoSQL database that can act as a spring framework cache provider on top of the spring framework cache abstraction layer. Caching improves the overal performance of an application.
Say you have long running CPU or I/O bound tasks you are invoking multiple times, you’re actually wasting valuable resources of the system. Instead of invoking these methods over and over again, it is better to cache them. In the following example we demonstrate a Couchbase Caching example configuration using Spring Boot.
Maven Dependencies
We use Apache Maven to manage our project dependencies. To start, make sure you include the following dependencies.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.memorynotfound.springboot.caching</groupId>
<artifactId>couchbase</artifactId>
<version>1.0.0-SNAPSHOT</version>
<url>https://memorynotfound.com</url>
<name>Spring Boot - ${project.artifactId}</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
</parent>
<dependencies>
<!-- Spring Framework Caching Support -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.couchbase.client</groupId>
<artifactId>java-client</artifactId>
</dependency>
<dependency>
<groupId>com.couchbase.client</groupId>
<artifactId>couchbase-spring-cache</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Downloading and Running Couchbase
In this tutorial we use Couchbase, which is a NoSQL database. In case you haven’t installed it locally, you can download the Couchbase server here. During this tutorial, make sure the Couchbase server is running. By default when you start Couchbase
it starts at port 8091
and you can access it using the following URL http://localhost:8091/ui/index.html#/overview
. When Couchbase is installed, configured and up and running, you should see the following screen.
Couchbase Caching Service
To illustrate this with an example, we wrote a simple play
method. This method is annotated with the @Cacheable
annotation, meaning this method will be cached upon subsequent invocations and if the specified condition is true
.
package com.memorynotfound.springboot;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.*;
import org.springframework.stereotype.Service;
@Service
public class MusicService {
private static Logger log = LoggerFactory.getLogger(MusicService.class);
@CacheEvict(cacheNames = CacheConfig.CACHE_NAME, allEntries = true)
public void evictCache(){}
@Cacheable(cacheNames = CacheConfig.CACHE_NAME, condition = "#instrument.equals('trombone')")
public String play(String instrument) {
log.info("Executing: " + this.getClass().getSimpleName() + ".play(\"" + instrument + "\");");
return "paying " + instrument + "!";
}
}
Couchbase Caching Configuration
To successfully connect to Couchbase
we need to configure a Cluster
. This cluster (Couchbase Server) needs to be running locally in this example. Next, we configure the Bucket
to where the CacheManager
‘ll be reading and writing from/to. Finally we use this Bucket
and Cluster
to create a CacheManger
. Make sure you annotate a configuration class with the @EnableCaching
annotation. This enables the caching in our application.
package com.memorynotfound.springboot;
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;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@EnableCaching
@Configuration
public class CacheConfig {
public static final String CACHE_NAME = "instruments";
@Bean(destroyMethod = "disconnect")
public Cluster cluster() {
// connect to the couchbase-server running on your local machine
return CouchbaseCluster.create();
}
@Bean(destroyMethod = "close")
public Bucket bucket() {
// connect to the bucket named 'default' (which must exist on your Couchbase server)
// every cache related element will use this bucket
return cluster().openBucket("default", "");
}
@Bean
public CacheManager cacheManager() {
CacheBuilder cacheBuilder = CacheBuilder.newInstance(bucket()).withExpiration(0);
return new CouchbaseCacheManager(cacheBuilder, CACHE_NAME);
}
}
Bootstrap Couchbase Caching Application
Now that we successfully configured Couchbase Caching, we can finally test if the configuration is working. We demonstrate this using the following application.
package com.memorynotfound.springboot;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application implements CommandLineRunner {
private static Logger log = LoggerFactory.getLogger(Application.class);
@Autowired
private MusicService musicService;
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... args) throws Exception {
log.info("Spring Boot Couchbase Caching Example Configuration");
musicService.evictCache();
play("trombone");
play("guitar");
play("trombone");
play("bass");
play("trombone");
}
private void play(String instrument){
log.info("Calling: " + MusicService.class.getSimpleName() + ".play(\"" + instrument + "\");");
musicService.play(instrument);
}
}
Console Output
The previous application prints the following output to the console. First, we see the connection to Couchbase is successful. Afterwards, we see that Couchbase successfully cached the play method when the trombone argument is passed.
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.4.RELEASE)
INFO - CouchbaseEnvironment: {sslEnabled=false, sslKeystoreFile='null', sslKeystorePassword=false, sslKeystore=null, bootstrapHttpEnabled=true, bootstrapCarrierEnabled=true, bootstrapHttpDirectPort=8091, bootstrapHttpSslPort=18091, bootstrapCarrierDirectPort=11210, bootstrapCarrierSslPort=11207, ioPoolSize=8, computationPoolSize=8, responseBufferSize=16384, requestBufferSize=16384, kvServiceEndpoints=1, viewServiceEndpoints=1, queryServiceEndpoints=1, searchServiceEndpoints=1, ioPool=NioEventLoopGroup, coreScheduler=CoreScheduler, memcachedHashingStrategy=DefaultMemcachedHashingStrategy, eventBus=DefaultEventBus, packageNameAndVersion=couchbase-java-client/2.3.7 (git: 2.3.7, core: 1.3.7-dirty), dcpEnabled=false, retryStrategy=BestEffort, maxRequestLifetime=75000, retryDelay=ExponentialDelay{growBy 1.0 MICROSECONDS, powers of 2; lower=100, upper=100000}, reconnectDelay=ExponentialDelay{growBy 1.0 MILLISECONDS, powers of 2; lower=32, upper=4096}, observeIntervalDelay=ExponentialDelay{growBy 1.0 MICROSECONDS, powers of 2; lower=10, upper=100000}, keepAliveInterval=30000, autoreleaseAfter=2000, bufferPoolingEnabled=true, tcpNodelayEnabled=true, mutationTokensEnabled=false, socketConnectTimeout=1000, dcpConnectionBufferSize=20971520, dcpConnectionBufferAckThreshold=0.2, dcpConnectionName=dcp/core-io, callbacksOnIoPool=false, disconnectTimeout=25000, requestBufferWaitStrategy=com.couchbase.client.core.env.DefaultCoreEnvironment$2@25cc7470, queryTimeout=75000, viewTimeout=75000, kvTimeout=2500, connectTimeout=5000, dnsSrvEnabled=false}
INFO - Connected to Node localhost
INFO - Opened bucket default
INFO - Registering beans for JMX exposure on startup
INFO - Spring Boot Couchbase Caching Example Configuration
INFO - Calling: MusicService.play("trombone");
INFO - Executing: MusicService.play("trombone");
INFO - Calling: MusicService.play("guitar");
INFO - Executing: MusicService.play("guitar");
INFO - Calling: MusicService.play("trombone");
INFO - Calling: MusicService.play("bass");
INFO - Executing: MusicService.play("bass");
INFO - Calling: MusicService.play("trombone");
INFO - Started Application in 2.595 seconds (JVM running for 3.095)
INFO - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@1e6a3214: startup date [Thu Jun 15 12:51:13 CEST 2017]; root of context hierarchy
INFO - Unregistering JMX-exposed beans on shutdown
INFO - Closed bucket default
INFO - Disconnected from Node localhost
INFO - Shutdown Core Scheduler: success
INFO - Shutdown Runtime Metrics Collector: success
INFO - Shutdown Latency Metrics Collector: success
INFO - Shutdown IoPool: success
INFO - Shutdown Netty: success
References
- Couchbase
- Spring Caching Documentation
- Couchbase Spring Cache Github
- Cluster JavaDoc
- Bucket JavaDoc
- CouchbaseCluster JavaDoc