In this blog post, we'll discover how to cache data easily using Spring Cache and Couchbase as a backing store.

Table of Content

A Word Of Introduction

There was a lot of work related to Spring lately! We've been busy working on the Spring Data Couchbase connector to upgrade it to the 2.x generation of the Java SDK, bringing along a host of new features and improvements (but more on that in a later blog post)…

Along the way, it came to our attention that there are a few classes in the project that are not really related directly to Spring Data and as such didn't need to adhere to its formal “Release Train” release cycle: the cache package.

So we started a new simple project to host the 2.x generation of the Couchbase Spring Cache implementation on github (couchbaselabs/couchbase-spring-cache).

Let's have a look at how it can be leveraged to easily introduce Couchbase-backed caching into a Spring project!

The Cache Abstraction

Spring Framework comes with a lightweight abstraction of a Cache that developers can automatically use by annotating methods in their classes (eg. in a @Repository stereotype).

In order to make use of the caching mechanisms, you simply annotate your methods with a handful of cache-related annotations:

  • @Cacheable will let the first invocation of the annotated method with a particular set of input parameter execute, but the result will be cached and subsequent invocations (with the same set) will be served transparently from the cache.
  • @CachePut will always invoke the method and cache its result (unlike @Cacheable it doesn't optimize the invocation flow).
  • @CacheEvict will compute a cache key from the annotated method's parameters and remove it from the cache when the method is executed (eg. because invoking this method makes an entry stale).
  • @Caching allows to regroup behavior from the previous annotation into a single one.
  • @CacheConfig allows to have common cache parameters set on a whole class.

The Couchbase Implementation

The abstract mechanism is put in place by the framework, but an actual backing implementation must be chosen. Spring comes with a few of them (in memory Map, EhCache, Gemfire…), but it is absolutely possible to define custom ones, simply by implementing a Cache and a CacheManager and making it visible in the Spring context.

That's the focus of couchbase-spring-cache.

Each cache has a name, and each value in the cache has a cache key. The Couchbase implementation will translate that into a document key that reflects that…

  • this is a Cache related document (by default using the prefix “cache:“)
  • it relates to a particular Cache (by adding the CACHE_NAME to the prefix above)
  • it stores a particular cache value under CACHE_KEY (so all in all “cache:CACHE_NAME:CACHE_KEY“).

For now the values must be Serializable and are stored as a SerializableDocument from the 2.x Java SDK, but alternative transcoding could be offered in the future, eg. JSON/JsonDocument

Getting couchbase-spring-cache and Putting it to Work

Note:

As of this writing the project is currently in 1.0-SNAPSHOT version so it is not available on Maven Central yet. You'll have to manually build the jar and add it to your local Maven repository.

Downloading and building the couchbase-spring-cache project

Start by cloning the project from github:

Then build and install it locally using Maven:

You should see a success message indicating the version built and where it was installed:

 

Starting a Tutorial Project

We'll build a sample project using Maven and Spring Boot as a base.
Start by creating the following directory structure for the project in a root directory of your choosing (we'll use cbcache here):

For instance, use the following command:

Then initiate the POM at the cbcache root in pom.xml with the following content:

Add Book Management Entity and Repository

We'll use the example of a Book repository (as found in the “GETTING STARTED – Caching Data with Spring” official guide from Spring.io).

Create the Book entity class in src/main/java/com/couchbase/demo/Book.java:

Note the Book class is Serializable, this is important for now for Couchbase storage.

Create a simple repository interface and a naive implementation that simulates a delay:

in src/main/java/com/couchbase/demo/BookRepository.java:

in src/main/java/com/couchbase/demo/SimpleBookRepository.java:

The Main Spring Boot Application

Finally, create an Application that uses the repository in src/main/java/com/couchbase/demo/Application.java:

If you run the Application's main method in your IDE (or if you invoke “mvn spring-boot:run” from the command line), you'll notice that all the calls are indeed quite slow:

Adding Caching Capabilities

In order to enable caching, you must take a few steps: first you must offer Spring a CacheManager @Bean

Since we'll be using the CouchbaseCacheManager (of course), we'll need to connect to a Cluster and use a Bucket reference (the storage unit where couchbase will store cache documents).
So the CouchbaseCacheManager needs a mapping between Cache names and the corresponding Bucket to use, passed as a Map.

In src/main/java/com/couchbase/demo/Application.java, add the following bean declarations:

You then want to activate the scanning of cache-related annotations and associated proxying by putting the @EnableCaching annotation on the Application class.

Activate Caching in SimpleBookRepository

Let's see how to activate actual caching on our SimpleBookRepository and verify how the application behaves after that.

To make getByIsbn automatically cache on first invocation and serve subsequent invocations with data from the cache, simply annotate it like so:

Let's run the application again and see how it behaves now:

Wow! This is much better for invocations past the first one, looks like it is indeed cached 🙂

Seeing the Data in Couchbase

Let's have a quick look at the webconsole to verify that these great timings can be attributed to Couchbase:

  • open a new tab in your browser and navigate to http://localhost:8091.
  • connect to the web console.
  • go to the Data Buckets tab and click on the Documents button for the bucket you elected to use (“default”).

What you see in this screen (quick link for the lazies) should be similar to this:

Spring Cache documents in Couchbase console

We can see that both books were cached in couchbase, using the cache:CACHE_NAME:CACHE_KEY pattern for the document IDs.

Conclusion

Easy caching using Couchbase is now at your fingertips!

There is much more that Spring Cache can do for you (for instance, choosing how to create the cache key, conditional caching, cache eviction, etc…), and there are specificities to couchbase-spring-cache (eg. for cache clearing you can choose between using a view that will only remove relevant document or, if your bucket is dedicated to a single cache, use the flush mechanism…).

I hope this introductory tutorial whetted your appetite for easy caching using Spring Cache and Couchbase!

The next steps will probably be to introduce alternative storage formats (like JSON) and to offer the artifact on Maven Central or a similar publicly accessible Maven repository (Bintray anyone?)…

Watch out for Spring-related news in the near future!

In the meantime, happy coding 🙂

Posted by Simon Basle, Software Engineer, Pivotal

Simon Basl_ is a Paris-based Software Engineer working in the Spring team at Pivotal. Previously, he worked in the Couchbase Java SDK team. His interests span software design aspects (OOP, design patterns, software architecture), rich clients, what lies beyond code (continuous integration, (D)VCS, best practices), and reactive programming. He is also an editor for the French version of InfoQ.com.

Leave a reply