Spring Boot With Caffeine Cache

In this article of Spring Boot, we will look at how to integrate Spring Boot with Caffeine Cache. We will inspect the Spring Boot auto configuration feature with the ability to hook the Caffeine cache transparently.

 

Introduction

Caffeine is a high performance Java 8 based caching library providing a near optimal hit rate. It provides an in-memory cache very similar to the Google Guava API. Spring Boot Cache starters auto-configured a CaffeineCacheManager if it finds the Caffeine in the classpath. The Spring Framework provides support for transparently adding Caching to an application. Let’s see how to integrate Spring Boot with Caffeine Cache.

 

1. Maven dependencies

To enable Spring Boot support for Caffeine, we need to add following two dependencies in our Spring Boot application.

  1. Spring Boot caching stater.
  2. Caffeine cache provider.
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
    <version>2.7.0</version>
</dependency>

Refer to the Caffeine website for the latest release.

 

2. Service Setup.

Let’s create a simple Customer Service which will return customer information from the underlying system. We will add the Spring framework caching abstraction on this layer using Caffeine Cache. Let’s look at our service class:

public interface CustomerService {
    Customer getCustomer(final Long customerID);
}
// Implementation
@Service
@CacheConfig(cacheNames = {"customer"})
public class DefaultCustomerService implements CustomerService {

    private static final Logger LOG = LoggerFactory.getLogger(DefaultCustomerService.class);

    @Cacheable
    @Override
    public Customer getCustomer(Long customerID) {
        LOG.info("Trying to get customer information for id {} ",customerID);
        return getCustomerData(customerID);
    }

    private Customer getCustomerData(final Long id){
        Customer customer = new Customer(id, "[email protected]", "Test Customer");
        return  customer;
    }
}

There are a few important point to discuss:

  1. The @CacheConfig is a class level annotation and help to streamline caching configurations.
  2. The @Cacheable annotation used to demarcate methods that are cacheable. In simple words, this annotation used to show caching API that we want to store results for this method into the cache so, on subsequent invocations, the value in the cache returned without execute the method.

[pullquote align=”normal”]If you are starting with caching, I highly recommend reading our article on the introduction to Spring Caching. [/pullquote]

Spring caching provides a very transparent way to enable caching. We have used no direct dependency from the Caffeine Cache in our code base, all these are taken care internally by Spring caching framework.

 

3. Caffeine Cache Configuration

Spring Boot provide several options to configure Caffeine cache on startup. We have the option to configure these properties either through configuration file (application.properties or yml) or programmatically. Let’s see how to configure Caffeine cache using application.properties file:

spring.cache.cache-names=ccustomer
spring.cache.caffeine.spec=maximumSize=500,expireAfterAccess=600s

The spring.cache.cache-names property creates customer caches. The Caffeine spec define the cache maximum size as 500 and a time to live of 10 minutes.

 

3.1 Caffeine Java Configuration

If you like, we can also configure Caffeine cache using Java configuration. Let’s see how the Java configuration look like:

@Configuration
public class CaffeineCacheConfig {

 @Bean
 public CacheManager cacheManager() {
  CaffeineCacheManager cacheManager = new CaffeineCacheManager("customer");
  cacheManager.setCaffeine(caffeineCacheBuilder());
  return cacheManager;
 }

 Caffeine < Object, Object > caffeineCacheBuilder() {
  return Caffeine.newBuilder()
   .initialCapacity(100)
   .maximumSize(500)
   .expireAfterAccess(10, TimeUnit.MINUTES)
   .weakKeys()
   .recordStats();
 }
}

 

4. Running Application

Let’s run our application to see it in action:

@Component
public class CaffeineCacheApp implements CommandLineRunner {

 private static final Logger LOG = LoggerFactory.getLogger(CaffeineCacheApp.class);

 @Autowired
 CustomerService customerService;

 @Override
 public void run(String...args) throws Exception {

  LOG.info("Starting the Caffine cache testing process");
  customerService.getCustomer(1 l); //No hit , since this is the first request.
  customerService.getCustomer(2 l); //No hit , since this is the first request.
  customerService.getCustomer(1 l); //hit , since it is already in the cache.
  customerService.getCustomer(1 l); //hit , since it is already in the cache.
  customerService.getCustomer(1 l); //hit , since it is already in the cache.
  customerService.getCustomer(1 l); //hit , since it is already in the cache.
 }
}

If you look at the output of the above program, this is how it look like:

2019-05-15 20:09:50.865  INFO 86848 --- [           main] com.javadevjournal.CaffeineCacheApp      : Starting the Caffeine cache testing process
2019-05-15 20:09:50.879  INFO 86848 --- [           main] c.j.service.impl.DefaultCustomerService  : Trying to get customer information for id 1 
2019-05-15 20:09:50.882  INFO 86848 --- [           main] c.j.service.impl.DefaultCustomerService  : Trying to get customer information for id 2

Once the customer data is in the cache, it serves all subsequent calls from the cache. Look at the logs, though we are calling getCustomer(1), multiple times but log statement got printed only once as all subsequent calls got served from the cache.

 

Summary

In this article, we saw how to integrate Spring Boot with Caffeine Cache. We checked the option to configure Caffeine using configuration files or through Java configuration. The source for this article is available on the GitHub.

5 thoughts on “Spring Boot With Caffeine Cache”

  1. Hi,
    thx for hint to Caffeine

    p.s.
    spring.cache.cache-names=ccustomer
    should be
    spring.cache.cache-names=customer

    i guess.

  2. 1. how to run the application. The app has 2 files one is @SpringBootApplication and one file which implements CommnadLineRunner.
    2. I built the jar and ran the application, could see the log lines getting print for every customerService.getCustomer()

Comments are closed.